package com.niiwoo.civet.trade.service.local.myloan;

import com.alibaba.dubbo.common.utils.Assert;
import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import com.niiwoo.activity.stage.service.prize.ActivityPrizeDubboService;
import com.niiwoo.civet.account.dto.common.BankCardDTO;
import com.niiwoo.civet.account.enums.AccountAmountTypeEnum;
import com.niiwoo.civet.account.enums.CanRefundEnum;
import com.niiwoo.civet.account.service.MoneyTotalDubboService;
import com.niiwoo.civet.account.service.bankcard.BankCardDubboService;
import com.niiwoo.civet.base.constant.OrgConstant;
import com.niiwoo.civet.base.enums.FeeTypeEnum;
import com.niiwoo.civet.base.enums.RefundTypeEnum;
import com.niiwoo.civet.base.utils.ProjectInfoUtil;
import com.niiwoo.civet.trade.constant.AmountHandleConstant;
import com.niiwoo.civet.trade.constant.DatePatternConstant;
import com.niiwoo.civet.trade.constant.enums.RefundedStatusEnum;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.*;
import com.niiwoo.civet.trade.dao.mapper.credit.CreditProjectMapperExt;
import com.niiwoo.civet.trade.dto.BorrowerPlanOverdueDTO;
import com.niiwoo.civet.trade.dto.ProjectBorrowerPlanNewDTO;
import com.niiwoo.civet.trade.dto.ProjectBorrowerPlanNewDetailDTO;
import com.niiwoo.civet.trade.dto.ProjectRepayTotalAmountDTO;
import com.niiwoo.civet.trade.dto.common.CurrMonthRefundPlanDTO;
import com.niiwoo.civet.trade.dto.common.ProjectBorrowerPlanDTO;
import com.niiwoo.civet.trade.dto.common.ProjectBorrowerSummaryDTO;
import com.niiwoo.civet.trade.dto.newRefund.RefundStateDTO;
import com.niiwoo.civet.trade.dto.request.ProjectFlowRequestDTO;
import com.niiwoo.civet.trade.dto.request.loan.RepaymentPlanDTO;
import com.niiwoo.civet.trade.dto.request.myloan.*;
import com.niiwoo.civet.trade.dto.response.SpeedLoanCreditAmountDTO;
import com.niiwoo.civet.trade.dto.response.invest.ProjectStartInvestAndIncreResponseDTO;
import com.niiwoo.civet.trade.dto.response.myloan.*;
import com.niiwoo.civet.trade.dto.response.myloan.QueryProjectBorrowDetailReponseDTO.*;
import com.niiwoo.civet.trade.dto.response.myloan.QueryRepaymentPlanResponseDTO.ProjectBorrowerPlanReponseDTO;
import com.niiwoo.civet.trade.dto.response.myloan.inner.BackToArticleDetails;
import com.niiwoo.civet.trade.dto.response.newRefund.OrgImmediateRepaymentResponseDTO;
import com.niiwoo.civet.trade.enums.*;
import com.niiwoo.civet.trade.service.invest.InvestDubboService;
import com.niiwoo.civet.trade.service.loan.SpeedLoanDubboService;
import com.niiwoo.civet.trade.service.local.common.ProjectCommonService;
import com.niiwoo.civet.trade.service.local.configure.TradeConfigLocalService;
import com.niiwoo.civet.trade.service.local.intelligenceInvest.ProjectPackageLocalService;
import com.niiwoo.civet.trade.service.local.kaola.KaoLaLiCaiRepayOrderService;
import com.niiwoo.civet.trade.service.local.kaola.KaoLaLiCaiRepaymentService;
import com.niiwoo.civet.trade.service.local.loan.LoanConfigService;
import com.niiwoo.civet.trade.service.local.newRefund.common.RefundCommonService;
import com.niiwoo.civet.trade.service.local.newRefund.common.RefundLocalService;
import com.niiwoo.civet.trade.service.local.newRefund.refundDeal.core.FeeCalcForRefundService;
import com.niiwoo.civet.trade.service.local.plan.BorrowerInvestorRepaymentContext;
import com.niiwoo.civet.trade.service.local.project.ProjectLocalService;
import com.niiwoo.civet.trade.service.local.refund.CommonLocalService;
import com.niiwoo.civet.trade.utils.ProjectUtil;
import com.niiwoo.civet.trade.utils.RepaymentUtil;
import com.niiwoo.civet.user.dto.request.SimpleOrgInfo;
import com.niiwoo.civet.user.dto.response.UserIdentityInfoResponseDTO;
import com.niiwoo.civet.user.service.OrganizationDubboService;
import com.niiwoo.civet.user.service.UserBasicInfoDubboService;
import com.niiwoo.civet.user.service.UserIdentityDubboService;
import com.niiwoo.tripod.provider.dto.response.PageResponseDTO;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.MathContext;
import java.text.ParseException;
import java.util.*;

@Service
@Slf4j
public class MyLoanLocalService {

    @Autowired
    private AuditAdditionalInfoMapperExt auditAdditionalInfoMapper;
    
    @Autowired
    private ProjectBorrowerPlanNewMapperExt projectBorrowerPlanNewMapperExt;

    @Autowired
    private ProjectBorrowerPlanDetailMapperExt projectBorrowerPlanDetailMapperExt;

    @Autowired
    private ProjectCommonService projectCommonService;

    @Autowired
    private RefundCommonService refundCommonService;

    @Autowired
    private FeeCalcForRefundService feeCalcForRefundService;

    @Reference(version = "1.0.0")
    private MoneyTotalDubboService moneyTotalDubboService;

    @Reference(version = "1.0.0")
    private SpeedLoanDubboService speedLoanDubboService;

    @Reference(version = "1.0.0")
    private UserBasicInfoDubboService userBasicInfoDubboService;

    @Reference(version = "1.0.0")
    private BankCardDubboService bankCardDubboService;

    @Reference(version = "1.0.0")
    private UserIdentityDubboService userIdentityDubboService;

    @Reference(version = "1.0.0")
    private InvestDubboService investDubboService;

    @Reference(version = "1.0.0")
    private ActivityPrizeDubboService activityPrizeDubboService;

    @Autowired
    private ProjectBorrowerSummaryMapperExt projectBorrowerSummaryMapperExt;

    @Autowired
    private ReturnProjectRecordMapperExt returnProjectRecordMapperExt;

    @Autowired
    private ProjectDynamicMapperExt dynamicMapperExt;

    @Autowired
    private ProjectInvestorPlanMapperExt projectInvestorPlanMapperExt;

    @Autowired
    private ProjectMapperExt projectMapperExt;

    @Autowired
    private ProjectInvestOrderMapperExt projectInvestOrderMapperExt;

    @Autowired
    private ProjectFlowedMapper projectFlowedMapper;

    @Autowired
    private ProjectContractMapperExt projectContractMapperExt;

    @Autowired
    private ProjectAuditDecisionMapperExt projectAuditDecisionMapper;

    @Autowired
    private BorrowerInvestorRepaymentContext borrowerInvestorRepaymentContext;

    @Autowired
    private CreditProjectMapperExt creditProjectMapperExt;

    @Autowired
    private ProjectAuditConfigMapperExt projectAuditConfigMapperExt;

    @Autowired
    private TradeConfigLocalService tradeConfigService;

    @Autowired
    private KaoLaInvestorMapperExt kaoLaInvestorMapperExt;
    @Autowired
    private CommonLocalService commonLocalService;
    @Autowired
    private KaoLaLiCaiRepaymentService kaoLaLiCaiRepaymentService;
    @Autowired
    private KaoLaLiCaiRepayOrderService kaoLaLiCaiRepayOrderService;
    @Autowired
    protected LoanConfigService loanConfigService;

    @Autowired
    private LoanVoucherAuditMapperExt loanVoucherAuditMapper;

    @Autowired
    private LoanVoucherAuditHisMapperExt loanVoucherAuditHisMapper;

    @Autowired
    private LoanVoucherImgMapperExt loanVoucherImgMapper;

    @Autowired
    private ProjectCreditAmountMapperExt projectCreditAmountMapper;

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    @Reference(version = "1.0.0")
    private OrganizationDubboService organizationDubboService;

    @Autowired
    private RefundLocalService refundLocalService;
    @Autowired
    private InvestAddInterestRateConfigMapperExt investAddInterestRateConfigMapperExt;
    @Autowired
    private ProjectPackageLocalService projectPackageLocalService;

    @Value("${h5-niiwoo-guarantee-model-url}")
    private String niiwooGuaranteeModelH5Url;
    

    @Value("${h5-risk-warning-url}")
    private String riskWarning;
    @Value("${h5-common-problem-url}")
    private String commonProblem;
    @Value("${h5-guarantee-model-url}")
    private String guaranteeModelH5Url;

    @Autowired
    private TradeConfigLocalService tradeConfigLocalService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    public LoanIndexQueryResponseDTO loanIndexQuery(String userId) {
        LoanIndexQueryResponseDTO loanIndexQueryResponseDTO = new LoanIndexQueryResponseDTO();
        try {
            // 日切时间
            Date currentDate = commonLocalService.getCurrentDate();

            // 查询是否有信用借借款记录
            Integer creditloanCount = creditProjectMapperExt.selectMyCreditloanCount(userId);
            loanIndexQueryResponseDTO.setHadCredit(creditloanCount > 0 ? (byte) 1 : (byte) 0);

            BigDecimal toRepayCurrentMonth = BigDecimal.ZERO; // 本月应还总额
            BigDecimal toRepayAmountTotal = BigDecimal.ZERO; // 应还款总额

            List<CurrMonthRefundPlanDTO> currMonthRefundPlanDTOList = projectBorrowerPlanNewMapperExt.selectShouldRefundProjectsWithPreData(userId);
            
        	// 借款首页需要显示的标的定义：当前时间可以申请还款的标的            
            List<CurrMonthRefundPlanDTO> filterCurrMonthRefundPlanDTOList = Lists.newArrayList();
            
            for (CurrMonthRefundPlanDTO currMonthRefundPlanDTO : currMonthRefundPlanDTOList) {
            	
            	// 过虑为没有到最早还款日的标的（注：预计应还日期减去一个自然月为标的最早还款日期）
				if (1 == currMonthRefundPlanDTO.getCurrentPeriod()
						|| (null != currMonthRefundPlanDTO.getRefundDate() && new DateTime(currentDate).plusMonths(1).toDate().after(currMonthRefundPlanDTO.getRefundDate()))) {
                	
	                filterCurrMonthRefundPlanDTOList.add(currMonthRefundPlanDTO);
	
	                if (ChannelCodeEnum.KAOLA.getChanelCode().equalsIgnoreCase(currMonthRefundPlanDTO.getChannelCode())) {
	                	// 待还金额
	                	BigDecimal totalAmount = kaoLaLiCaiRepaymentService.getImmediateRepayAmount(projectBorrowerSummaryMapperExt.selectByPrimaryKey(currMonthRefundPlanDTO.getProjectId()));
	                	currMonthRefundPlanDTO.setAmount(totalAmount);
	                	
	                	// 逾期天数
	                	currMonthRefundPlanDTO.setDays(kaoLaLiCaiRepaymentService.getKaolaOverdueDays(currMonthRefundPlanDTO.getRefundDate(), true));
	                	
	                	// 是否当前有正在还款的标的
	                	currMonthRefundPlanDTO.setCanRefund(kaoLaLiCaiRepayOrderService.isProcessing(currMonthRefundPlanDTO.getProjectId()).getCode());
	                } else {
	                	// 待还金额
	                    RefundStateDTO refundStateDTO = feeCalcForRefundService.caculateAmountRepaymentForAPP(currMonthRefundPlanDTO.getProjectId(), RefundTypeEnum.IMMEDIATELY);
	                    currMonthRefundPlanDTO.setAmount(refundStateDTO.getAmount());
	                    
	                    // 逾期天数
	                    currMonthRefundPlanDTO.setDays(RepaymentUtil.getOverdueDay(currentDate, currMonthRefundPlanDTO.getRefundDate()));
	                    
	                	// 是否当前有正在还款的标的
	                    currMonthRefundPlanDTO.setCanRefund(refundCommonService.checkCanRefund(currMonthRefundPlanDTO.getProjectId()).getCode());
	                }
	
	                // 是否显示立即结清按钮，借款期限为只有一期和严重逾期（坏帐）不显示，默认显示
	                currMonthRefundPlanDTO.setShowEarlyClearance((byte) 1);
	                if (currMonthRefundPlanDTO.getTotalPeriod() == 1 || RepayStatusEnum.BADLOANS.getCode().equals(currMonthRefundPlanDTO.getRepayStatus())) {
	                    currMonthRefundPlanDTO.setShowEarlyClearance((byte) 0);
	                }
	
	                // 考拉理财逾期的也不显示
	                if (ChannelCodeEnum.KAOLA.getChanelCode().equals(currMonthRefundPlanDTO.getChannelCode())
	                        && RepayStatusEnum.OVERDUE.getCode().equals(currMonthRefundPlanDTO.getRepayStatus())) {
	                    currMonthRefundPlanDTO.setShowEarlyClearance((byte) 0);
	                }
	
	                // 标的当前待还款金额
	                toRepayCurrentMonth = toRepayCurrentMonth.add(currMonthRefundPlanDTO.getAmount());
                }

                // 标的总待还款金额，如果是坏帐标的待还总金额等于当前应还总金额
				if (RepayStatusEnum.BADLOANS.getCode().equals(currMonthRefundPlanDTO.getRepayStatus())) {
					toRepayAmountTotal = toRepayAmountTotal.add(currMonthRefundPlanDTO.getAmount());
				} else {
	                ProjectRepayTotalAmountDTO projectRepayTotalAmountDTO = refundCommonService.getProjectTotalNeedRepayAmount(currMonthRefundPlanDTO.getProjectId(), userId);
	                toRepayAmountTotal = toRepayAmountTotal.add(projectRepayTotalAmountDTO.getTotalAmount());
				}
            }

            // 信用借额度暂时默认设置为0
            loanIndexQueryResponseDTO.setCreditLoanRemainAmount(BigDecimal.ZERO);

            loanIndexQueryResponseDTO.setToRepayCurrentMonth(toRepayCurrentMonth);
            loanIndexQueryResponseDTO.setToRepayAmountTotal(toRepayAmountTotal);
            loanIndexQueryResponseDTO.setCurrMonthRefundPlans(filterCurrMonthRefundPlanDTOList);
            
            //查询信用价值url
            Map<String, String> tradeConfig = tradeConfigService.selectTradeConfigByEmuns(TradeConfigEnum.CREDIT_VALUE_URL);
            if (tradeConfig != null && StringUtils.isNotBlank(tradeConfig.get(TradeConfigEnum.CREDIT_VALUE_URL.getConfigKey()))) {
            	loanIndexQueryResponseDTO.setCreditValueUrl(tradeConfig.get(TradeConfigEnum.CREDIT_VALUE_URL.getConfigKey()));
            }
            
            // 已还总额（帐户中心财富统计查询）
            BigDecimal repayedAmountTotal = moneyTotalDubboService.queryMoneyByUserIdAndAccountType(userId, AccountAmountTypeEnum.REPAYMENT_TOTAL);
            loanIndexQueryResponseDTO.setRepayedAmountTotal(repayedAmountTotal);
            
            // 极速借额度
            SpeedLoanCreditAmountDTO speedLoanCreditAmountDTO = speedLoanDubboService.getSpeedLoanCreditAmount(userId);            
            BigDecimal fastLoanRemainAmount = speedLoanCreditAmountDTO.getCreditTotalAmount().subtract(speedLoanCreditAmountDTO.getCreditUsedAmount());
            loanIndexQueryResponseDTO.setFastLoanRemainAmount(fastLoanRemainAmount.max(BigDecimal.ZERO));

            // 银行卡后四位信息
            BankCardDTO bankCardDTO = bankCardDubboService.getUserBankCardInfo(userId);
            String bankCode = bankCardDTO.getBankAccountNo();
            loanIndexQueryResponseDTO.setBankAccountLast(bankCode.substring(bankCode.length() - 4));
        } catch (Exception e) {
            log.error("用户查询我的借款首页异常，异常原因：{}，UserId:{}", e.getMessage(), userId, e);
        }

        return loanIndexQueryResponseDTO;
    }

    /**
     * 按日期查询还款计划
     *
     * @param myloanRequestDTO
     * @return
     */
    public PageResponseDTO<LoanPlanDateResponseDTO> loanPlanDateQuery(MyloanRequestDTO myloanRequestDTO) {
        PageResponseDTO<LoanPlanDateResponseDTO> result = new PageResponseDTO<>();

        Integer count = projectBorrowerPlanNewMapperExt.selectLoanPlanDateCount(myloanRequestDTO.getUserId());
        List<LoanPlanDateResponseDTO> loanPlanDateResponseDTOList = Lists.newArrayList();
        if (count > 0) {
            loanPlanDateResponseDTOList.addAll(projectBorrowerPlanNewMapperExt.selectLoanPlanDateList(myloanRequestDTO.getUserId(), myloanRequestDTO.getOffset(), myloanRequestDTO.getPageSize()));
        }
        result.measureTotalPage(count, myloanRequestDTO.getPageSize());
        result.setItems(loanPlanDateResponseDTOList);

        return result;
    }

    /**
     * 按月份查询还款计划
     *
     * @param myloanRequestDTO
     * @return
     */
    public PageResponseDTO<LoanPlanMonthResponseDTO> loanPlanMonthQuery(MyloanRequestDTO myloanRequestDTO) {
        PageResponseDTO<LoanPlanMonthResponseDTO> result = new PageResponseDTO<>();

        Integer count = projectBorrowerPlanNewMapperExt.selectLoanPlanMonthCount(myloanRequestDTO.getUserId());
        List<LoanPlanMonthResponseDTO> loanPlanMonthResponseDTOList = Lists.newArrayList();
        if (count > 0) {
            loanPlanMonthResponseDTOList.addAll(projectBorrowerPlanNewMapperExt.selectLoanPlanMonthList(myloanRequestDTO.getUserId(), myloanRequestDTO.getOffset(),
                    myloanRequestDTO.getPageSize()));
        }
        result.measureTotalPage(count, myloanRequestDTO.getPageSize());
        result.setItems(loanPlanMonthResponseDTOList);
        return result;
    }

    /**
     * 查询用户未结清的借款数量
     *
     * @param userId
     * @return
     */
    public Integer queryNotSettlementLoanCount(String userId) {
        List<Byte> statusList = Lists.newArrayList();
        statusList.add(ProjectStatusEnum.CHECKING.getStatus());
        statusList.add(ProjectStatusEnum.COLLECTING.getStatus());
        statusList.add(ProjectStatusEnum.REPAYING.getStatus());
        return projectCommonService.statisticsProjectCountByStatus(userId, statusList, null);
    }

    /**
     * 我的借款列表
     * 
     * @param dto
     * @return
     */
    public PageResponseDTO<LoanGoingResponseDTO> myloanGoingQuery(MyloanRequestDTO dto) {
        PageResponseDTO<LoanGoingResponseDTO> result = new PageResponseDTO<>();

        int count = projectBorrowerPlanNewMapperExt.selectMyloanGoingCount(dto.getUserId());

        Date currentDate = commonLocalService.getCurrentDate();
        
        List<LoanGoingResponseDTO> loanGoingResponseDTOList = Lists.newArrayList();
		List<LoanGoingResponseDTO> loanGoingResponseDTOForDBList = projectBorrowerPlanNewMapperExt.selectMyloanGoings(dto.getUserId(), dto.getOffset(), dto.getPageSize());
        
        for (LoanGoingResponseDTO loanGoingResponseDTO : loanGoingResponseDTOForDBList) {
        	
        	// 用户提前还款，当前期还没有到最早还款日期时显示上一期
			if (null != loanGoingResponseDTO.getCurrentPeriod() && loanGoingResponseDTO.getCurrentPeriod() > 0
					&& null != loanGoingResponseDTO.getRefundDate() && !new DateTime(currentDate).plusMonths(1).toDate().after(loanGoingResponseDTO.getRefundDate())) {
            	loanGoingResponseDTO = projectBorrowerPlanNewMapperExt.selectMyloanGoingsByProjectIdAndPeriod(loanGoingResponseDTO.getProjectId(), loanGoingResponseDTO.getCurrentPeriod());
            }

            if (ChannelCodeEnum.KAOLA.getChanelCode().equalsIgnoreCase(loanGoingResponseDTO.getChannelCode())) {
                loanGoingResponseDTO.setRefundStatus(RefundedStatusEnum.INIT.getStatus());
                
                // 计算待还金额
                BigDecimal totalAmount = kaoLaLiCaiRepaymentService.getImmediateRepayAmount(projectBorrowerSummaryMapperExt.selectByPrimaryKey(loanGoingResponseDTO.getProjectId()));
                loanGoingResponseDTO.setCapital(totalAmount);
                loanGoingResponseDTO.setManagementFee(BigDecimal.ZERO);
                loanGoingResponseDTO.setGuaranteeFee(BigDecimal.ZERO);
                loanGoingResponseDTO.setInterest(BigDecimal.ZERO);
                loanGoingResponseDTO.setPenaltyFee(BigDecimal.ZERO);
                
                // 判断当时标是否有正在进行还款操作                    
                loanGoingResponseDTO.setCanRefund(kaoLaLiCaiRepayOrderService.isProcessing(loanGoingResponseDTO.getProjectId()).getCode());
                
                // 还款时间不为空时计算逾期天数
                if (Objects.nonNull(loanGoingResponseDTO.getRefundDate())) {
                	loanGoingResponseDTO.setDays(kaoLaLiCaiRepaymentService.getKaolaOverdueDays(loanGoingResponseDTO.getRefundDate(), true));
                }
                
                // 法大大合同查询地址
                loanGoingResponseDTO.setViewUrl(projectContractMapperExt.findNewestByProjectIdAndContractType(loanGoingResponseDTO.getProjectId(), (byte) 8));                	
            } else {
            	// 计算待还金额
				if (ProjectStatusEnum.REPAYING.getStatus().equals(loanGoingResponseDTO.getStatus()) && Objects.nonNull(loanGoingResponseDTO.getRefundDate())) {
					
					// 还款中且为坏帐，直接标记还款状态为：未还款
			    	if (ProjectSubStatusEnum.REPAYING_BAD.getSubStatus() == loanGoingResponseDTO.getSubStatus()) {
			    		loanGoingResponseDTO.setRefundStatus((byte) 1);
			    	}
					
                    RefundStateDTO refundStateDTO = feeCalcForRefundService.caculateAmountRepaymentForAPP(loanGoingResponseDTO.getProjectId(), RefundTypeEnum.IMMEDIATELY);
                    loanGoingResponseDTO.setCapital(refundStateDTO.getAmount());
                    loanGoingResponseDTO.setInterest(BigDecimal.ZERO);
                    loanGoingResponseDTO.setPenaltyFee(BigDecimal.ZERO);
                    loanGoingResponseDTO.setManagementFee(BigDecimal.ZERO);
                    loanGoingResponseDTO.setGuaranteeFee(BigDecimal.ZERO);
                    
                    loanGoingResponseDTO.setDays(RepaymentUtil.getOverdueDay(currentDate, loanGoingResponseDTO.getRefundDate()));                		
            	}
				
				// 是否可以发起还款
				loanGoingResponseDTO.setCanRefund(refundCommonService.checkCanRefund(loanGoingResponseDTO.getProjectId()).getCode());
                
                // 法大大合同查询地址
                loanGoingResponseDTO.setViewUrl(getFadadaBorrowContractUrl(loanGoingResponseDTO.getProjectId()));
            }

            // 发布时间，还款中与已结清标的显示满标时间，投资中的显示上标时间、默认显示标创建时间
            Date publishTime = loanGoingResponseDTO.getCreateTime();
			if (ProjectStatusEnum.REPAYING.getStatus().equals(loanGoingResponseDTO.getStatus())
					|| ProjectStatusEnum.FINISH.getStatus().equals(loanGoingResponseDTO.getStatus())) {
                publishTime = loanGoingResponseDTO.getFullSuccessTime();
            } else if (ProjectStatusEnum.COLLECTING.getStatus().equals(loanGoingResponseDTO.getStatus())) {
                publishTime = loanGoingResponseDTO.getPublishTime();
            }
			loanGoingResponseDTO.setPublishTime(publishTime);                

			// 银行卡信息
			try {
				BankCardDTO bankCardDTO = bankCardDubboService.getUserBankCardInfo(dto.getUserId());
				loanGoingResponseDTO.setBankCard(bankCardDTO.getBankAccountNo());
			} catch (Exception e) {
				log.error("查询进行中借款列表异常，异常原因：调用帐户中心查询绑定银行卡信息异常，UserId:{}", dto.getUserId());
			}

            loanGoingResponseDTO.setProjectTitle(ProjectInfoUtil.getLoanUsage(loanGoingResponseDTO.getProjectTitle()));

            loanGoingResponseDTOList.add(loanGoingResponseDTO);				
		}
        
        result.measureTotalPage(count, dto.getPageSize());
        result.setItems(loanGoingResponseDTOList);
        return result;
    }

    /**
     * 获取法大大借款合同地址
     * @param projectId
     * @return
     */
    private String getFadadaBorrowContractUrl(Long projectId) {
        String contractUrl = "";

        Project project = projectMapperExt.selectByPrimaryKey(projectId);
        if (ProjectTypeEnum.ORG_SPEEDLOAN_NEW.getValue().equals(project.getType())) { //极速借机构
            //军拓
            if(OrgConstant.JUNTUO_ORG_ID.equals(project.getOrgId()) && PeriodUnitEnum.DAY.getValue().equals(project.getDeadlineUnit())){
                if (BorrowerTypeEnum.PERSONAL.getType().equals(project.getBorrowerType())) { // 个人标
                    contractUrl = projectContractMapperExt.findNewestByProjectIdAndContractType(projectId, FadadaContractTemplateEnum.TemplateTypeEnum.JUN_TUO_PERSONAL_FAST_LOAN.getType());
                } else if (BorrowerTypeEnum.COMPANY.getType().equals(project.getBorrowerType())) { // 企业标
                    contractUrl = projectContractMapperExt.findNewestByProjectIdAndContractType(projectId, FadadaContractTemplateEnum.TemplateTypeEnum.JUN_TUO_COMPANY_FAST_LOAN.getType());
                }
            } else {//鸿特
                if (BorrowerTypeEnum.PERSONAL.getType().equals(project.getBorrowerType())) { // 个人标
                    contractUrl = projectContractMapperExt.findNewestByProjectIdAndContractType(projectId, FadadaContractTemplateEnum.TemplateTypeEnum.ORG_PERSONAL_FAST_LOAN.getType());
                } else if (BorrowerTypeEnum.COMPANY.getType().equals(project.getBorrowerType())) { // 企业标
                    contractUrl = projectContractMapperExt.findNewestByProjectIdAndContractType(projectId, FadadaContractTemplateEnum.TemplateTypeEnum.ORG_COMPANY_FAST_LOAN.getType());
                }
            }
        } else if (ProjectTypeEnum.DECORATION_LOAN.getValue().equals(project.getType())) { // 土巴兔
            contractUrl = projectContractMapperExt.findNewestByProjectIdAndContractType(projectId, FadadaContractTemplateEnum.TemplateTypeEnum.TO8TO_FAST_LOAN.getType());
        } else {
            contractUrl = projectContractMapperExt.findNewestByProjectIdAndContractType(projectId, FadadaContractTemplateEnum.TemplateTypeEnum.FAST_LOAN.getType());
        }

        return contractUrl;
    }

    public PageResponseDTO<LoanEndResponseDTO> myloanEndedQuery(MyloanRequestDTO dto) {
        PageResponseDTO<LoanEndResponseDTO> result = new PageResponseDTO<>();

        int count = projectMapperExt.selectMyloanEndedCount(dto.getUserId());
        List<LoanEndResponseDTO> list = new ArrayList<>();
        if (count > 0) {
            list.addAll(projectMapperExt.selectMyloanEndeds(dto.getUserId(), dto.getOffset(), dto.getPageSize()));
            if (CollectionUtils.isNotEmpty(list)) {

                list.forEach(v -> {
                    if (ChannelCodeEnum.KAOLA.getChanelCode().equalsIgnoreCase(v.getChannelCode())) {
                        v.setViewUrl(projectContractMapperExt.findNewestByProjectIdAndContractType(v.getProjectId(), (byte) 8));
                    } else {
                        v.setViewUrl(getFadadaBorrowContractUrl(v.getProjectId()));
                    }
                    v.setProjectTitle(ProjectInfoUtil.getLoanUsage(v.getProjectTitle()));
                });
            }
        }
        result.measureTotalPage(count, dto.getPageSize());
        result.setItems(list);

        return result;
    }

    /**
     * @param status
     * @param subStatus
     * @return
     */
    private ProjectDisplayStatusEnum getDisplayStatus(Byte status, Integer subStatus) {
        ProjectStatusEnum statusEnum = ProjectStatusEnum.enumOf(status);
        ProjectSubStatusEnum subStatusEnum = ProjectSubStatusEnum.enumOf(subStatus);
        switch (statusEnum) {
            case CHECKING:
                switch (subStatusEnum) {
                    case CHECKING_BACK:
                        return ProjectDisplayStatusEnum.BACK;
                    case CHECKING_BACK_PHONEOPERATOR_TIMEOUT:
                        return ProjectDisplayStatusEnum.BACK;
                    case CHECKING_BACK_ADDRESSLIST_TIMEOUT:
                        return ProjectDisplayStatusEnum.BACK;
                    case CHECKING_FOR_CONFIRM:
                        return ProjectDisplayStatusEnum.TO_BE_CONFIRMED;
                    default:
                        return ProjectDisplayStatusEnum.CHECKING;
                }
            case COLLECTING:
                return ProjectDisplayStatusEnum.COLLECTING;
            case REPAYING:
                switch (subStatusEnum) {
                    case REPAYING_INIT:
                        return ProjectDisplayStatusEnum.REPAYING;
                    case REPAYING_OVERDUE:
                        return ProjectDisplayStatusEnum.OVERDUE_REPAYING;
                    default:
                        return ProjectDisplayStatusEnum.BAD_DEBT;
                }
            case FINISH:
                switch (subStatusEnum) {
                    case FINISH_BAD:
                        return ProjectDisplayStatusEnum.BAD_DEBT_FINISH;
                    default:
                        return ProjectDisplayStatusEnum.FINISH;
                }
            case MISCARRY:
                return ProjectDisplayStatusEnum.MISCARRY;

            default:
                return null;
        }
    }

    private DetailBadDebt getDetailBadDebt(Project project, ProjectDisplayStatusEnum disStatus) {
    	
    	// 当前日切时间
    	Date currentDate = commonLocalService.getCurrentDate();
    	
        DetailBadDebt result = new DetailBadDebt();
        result.setFullSuccessTime(DateFormatUtils.format(project.getFullSuccessTime(), DatePatternConstant.YYYY_MM_DD_HH_MM));
        result.setContractAmount(project.getContractAmount());
        result.setBorrowRate(project.getBorrowRate().multiply(BigDecimal.valueOf(AmountHandleConstant.HUNDRED))
                .setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN));
        result.setDeadline(project.getDeadline());
        result.setDeadlineUnit(project.getDeadlineUnit());
        result.setPublishTime(DateFormatUtils.format(project.getPublishTime(), DatePatternConstant.YYYY_MM_DD_HH_MM));
        result.setChannelCode(project.getChannelCode());
        result.setFromSource(project.getFromSource());
        result.setBizType(project.getType());

        ProjectBorrowerSummary projectBorrowerSummary = projectBorrowerSummaryMapperExt.selectByPrimaryKey(project.getProjectId());
        result.setCurrentPeriod(projectBorrowerSummary.getCurrentPeriod());
        result.setTotalPeriod(projectBorrowerSummary.getTotalPeriod());

        // 金额信息
        BigDecimal capitalTotal = BigDecimal.ZERO;
        BigDecimal interestTotal = BigDecimal.ZERO;
        BigDecimal penaltyFeeTotal = BigDecimal.ZERO;
        BigDecimal managementFeeTotal = BigDecimal.ZERO;
        BigDecimal guaranteeFeeTotal = BigDecimal.ZERO;

        boolean isOverdueFlag = false;
        boolean isBadDebt = false;
        boolean firstOverdueFlag = false;
        boolean badDebtFlag = false;
        Integer firstPeriodOverdueDay = 0;
        Integer overduePeriod = null;

        // 查询当前还款计划详情
        List<ProjectBorrowerPlanNewDTO> projectBorrowerPlanNewDTOList = projectBorrowerPlanNewMapperExt.selectByProjectIdForAmount(project.getProjectId());
        
        for (ProjectBorrowerPlanNewDTO projectBorrowerPlanNewDTO : projectBorrowerPlanNewDTOList) {
        	// 非还款中的直接跳过
            if (!BorrowerPlanRefundStatusEnum.NON_REPAYMENT.getCode().equals(projectBorrowerPlanNewDTO.getStatus())) {
            	continue;
            }
            
            // 累计待还总金额
            capitalTotal = capitalTotal.add(projectBorrowerPlanNewDTO.getCapital().subtract(projectBorrowerPlanNewDTO.getRefundedCapital()));
            interestTotal = interestTotal.add(projectBorrowerPlanNewDTO.getInterest().subtract(projectBorrowerPlanNewDTO.getRefundedInterest()));
            penaltyFeeTotal = penaltyFeeTotal.add(projectBorrowerPlanNewDTO.getPenaltyFee()).subtract(projectBorrowerPlanNewDTO.getRefundedPenaltyFee());
            managementFeeTotal = managementFeeTotal.add(projectBorrowerPlanNewDTO.getManagementFee().subtract(projectBorrowerPlanNewDTO.getRefundedManagementFee()));
            guaranteeFeeTotal = guaranteeFeeTotal.add(projectBorrowerPlanNewDTO.getGuaranteeFee().subtract(projectBorrowerPlanNewDTO.getRefundedGuaranteeFee()));
            
            // 当前期
            if (projectBorrowerSummary.getCurrentPeriod().equals(projectBorrowerPlanNewDTO.getPeriod())) {
            	// 当前期还款日期未到，直接标记成功
            	if (1 != projectBorrowerSummary.getCurrentPeriod() && !new DateTime(currentDate).plusMonths(1).toDate().after(projectBorrowerPlanNewDTO.getRefundDate())) {
                    result.setCurrentRefundStatus(RefundedStatusEnum.NORMAL_SUCCESS.getStatus());
                } else {
                	result.setCurrentRefundStatus(projectBorrowerPlanNewDTO.getStatus());
                }
                result.setCurrentPeriodRefundDate(projectBorrowerPlanNewDTO.getRefundDate());
				result.setRepayDateIsToday(DateUtils.isSameDay(projectBorrowerPlanNewDTO.getRefundDate(), currentDate));
                if (ChannelCodeEnum.KAOLA.getChanelCode().equalsIgnoreCase(project.getChannelCode())) {
                    Byte repayStatus = kaoLaLiCaiRepayOrderService.getRepayStatus(projectBorrowerPlanNewDTO.getProjectId(), projectBorrowerSummary.getCurrentPeriod());
                    Optional.ofNullable(repayStatus).ifPresent(result::setKaolaRepayStatus);
                }
            }
            
			if (ProjectDisplayStatusEnum.OVERDUE_REPAYING.equals(disStatus) || ProjectDisplayStatusEnum.BAD_DEBT.equals(disStatus)) {
                BorrowerPlanOverdueDTO borrowerPlanOverdueDTO = refundCommonService.getBorrowerPlanOverdueInfo(projectBorrowerPlanNewDTO, project);
                isOverdueFlag = borrowerPlanOverdueDTO.getIsOverdue();
                isBadDebt = borrowerPlanOverdueDTO.getIsBadloan();
                if (isBadDebt) {
                    isOverdueFlag = true;
                }
                
                // 逾期第一期数据
                if (isOverdueFlag && !firstOverdueFlag) {
                    firstOverdueFlag = true;
                    overduePeriod = projectBorrowerPlanNewDTO.getPeriod();
                    if (ChannelCodeEnum.KAOLA.getChanelCode().equalsIgnoreCase(project.getChannelCode())) {
                        firstPeriodOverdueDay = kaoLaLiCaiRepaymentService.getKaolaOverdueDays(projectBorrowerPlanNewDTO.getRefundDate());
                    } else {
                        firstPeriodOverdueDay = RepaymentUtil.getOverdueDay(projectBorrowerPlanNewDTO.getRefundDate(), commonLocalService.getCurrentDate());
                    }                    
					log.info("isOverdueFlag firstOverdueFlag projectId:{},refundDate:{},firstPeriodOverdueDay:{}",
							project.getProjectId(), projectBorrowerPlanNewDTO.getRefundDate(), firstPeriodOverdueDay);
                }
                
                // 坏帐标的截止时间
                if (ProjectDisplayStatusEnum.BAD_DEBT.equals(disStatus) && !badDebtFlag) {
                	badDebtFlag = true;
                    result.setEndTime(new DateTime(projectBorrowerPlanNewDTO.getRefundDate()).plusMonths(1).toString(DatePatternConstant.YYYY_MM_DD));
                }
            }
        }
        
        // 逾期
        if (firstOverdueFlag) {
			result.setPenaltyRate(project.getPenaltyRate().multiply(BigDecimal.valueOf(AmountHandleConstant.HUNDRED))
					.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN));
            result.setOverduePeriod(overduePeriod);
            result.setOverdueDay(firstPeriodOverdueDay);
        }
        
        // 罚息
        result.setPenaltyFee(penaltyFeeTotal);

        // 当期待还金额
        RefundStateDTO refundStateDTO = feeCalcForRefundService.caculateAmountRepaymentForAPP(project.getProjectId(), RefundTypeEnum.IMMEDIATELY);
        result.setCurrentPeriodCapital(refundStateDTO.getCapital());
        result.setCurrentPeriodInterest(refundStateDTO.getInterest());
        result.setCurrentPeriodManagementFee(refundStateDTO.getManageFee());
        result.setCurrentPeriodGuaranteeFee(refundStateDTO.getGuaranteeFee());
        result.setCurrentPeriodRefundTotalAmount(refundStateDTO.getAmount());       
        
        // 坏帐待还利息取当前期待还利息
        if (ProjectDisplayStatusEnum.BAD_DEBT.equals(disStatus)) {
			interestTotal = refundStateDTO.getInterest();
        }
        
        // 当前待还金额
        result.setPendingRepaymentTotalAmount(capitalTotal.add(interestTotal).add(penaltyFeeTotal).add(managementFeeTotal).add(guaranteeFeeTotal));
        result.setPendingRepaymentCapitalTotal(capitalTotal);
        result.setPendingRepaymentInterestTotal(interestTotal);
        result.setPendingRepaymentManagementFeeTotal(managementFeeTotal);
        result.setPendingRepaymentGuaranteeFeeTotal(guaranteeFeeTotal);
        
		// 银行卡信息
		try {
			BankCardDTO bankCardDTO = bankCardDubboService.getUserBankCardInfo(project.getBorrowUserId());
	        String bankAccountNoEndNum = bankCardDTO.getBankAccountNo();
	        if (StringUtils.isNotEmpty(bankAccountNoEndNum) && bankAccountNoEndNum.length() >= 4) {
	        	result.setBankAccountNoendNum(bankAccountNoEndNum.substring(bankAccountNoEndNum.length() - 4, bankAccountNoEndNum.length()));
	        }
		} catch (Exception e) {
			log.error("查询标的详情调用帐户中心查询绑定银行卡信息异常，UserId:{}", project.getBorrowUserId());
		}        

        return result;
    }

    /**
     * 借款详情-APP
     *
     * @param projectId
     * @param userId
     * @return
     */
    public QueryProjectBorrowDetailAPPReponseDTO queryProjectBorrowDetailAPP(Long projectId, String userId) {
        Assert.notNull(projectId, "queryProjectBorrowDetail projectId is null");
        Assert.notNull(projectId, "queryProjectBorrowDetail userId is null");

        QueryProjectBorrowDetailAPPReponseDTO result = new QueryProjectBorrowDetailAPPReponseDTO();

        Project project = projectMapperExt.selectByPrimaryKey(projectId);
        if (project == null) {
            throw new BizException("TRD20001");
        }
        ProjectBorrowerSummary projectBorrowerSummary = projectBorrowerSummaryMapperExt.selectByPrimaryKey(projectId);
        if (projectBorrowerSummary != null) {
            result.setCanRefund(refundCommonService.checkCanRefund(projectId).getCode());
        } else {
            result.setCanRefund(CanRefundEnum.CAN_REFUND.getCode());
        }

        result.setStatus(project.getStatus());
        result.setSubStatus(project.getSubStatus());
        result.setDisplayStatus(getDisplayStatus(project.getStatus(), project.getSubStatus()).getStatus());
        result.setProjectId(projectId);
        result.setContractAmount(project.getContractAmount());
        result.setProjectTitle(project.getTitle());
        result.setBorrowerType(project.getBorrowerType());

        String time = FastDateFormat.getInstance(DatePatternConstant.YYYY$MM$DD_HH_MM).format(project.getCreateTime()) + " 申请";
        ProjectStatusEnum statusEnum = ProjectStatusEnum.enumOf(project.getStatus());
        if (statusEnum == ProjectStatusEnum.COLLECTING && ProjectSubStatusEnum.COLLECTING_INIT == ProjectSubStatusEnum.enumOf(project.getSubStatus())) {
            time = FastDateFormat.getInstance(DatePatternConstant.YYYY$MM$DD_HH_MM).format(project.getPublishTime()) + " 发布";
        } else if (statusEnum == ProjectStatusEnum.REPAYING || statusEnum == ProjectStatusEnum.FINISH) {
            time = FastDateFormat.getInstance(DatePatternConstant.YYYY$MM$DD_HH_MM).format(project.getFullSuccessTime()) + " 满标";
        } else if (statusEnum == ProjectStatusEnum.COLLECTING
                && ProjectSubStatusEnum.COLLECTING_LENDING == ProjectSubStatusEnum.enumOf(project.getSubStatus())) {
            time = FastDateFormat.getInstance(DatePatternConstant.YYYY$MM$DD_HH_MM).format(project.getFullSuccessTime()) + " 满标";
        }
        result.setProjectTime(time);

        return result;
    }

    /**
     * 根据标的id获取项目详情(Jaylin)
     *
     * @param projectId
     * @return
     */
    public ProjectDetailResponseDTO queryProjectDetailByProjectId(Long projectId) {

        Project project = projectMapperExt.selectByPrimaryKey(projectId);
        Assert.notNull(project, "根据projectId未查询到此项目记录");

        ProjectDetailResponseDTO projectDetailResponseDTO = new ProjectDetailResponseDTO();
        projectDetailResponseDTO.setProjectId(projectId);
        projectDetailResponseDTO.setBorrowUserId(project.getBorrowUserId());
        projectDetailResponseDTO.setTitle(project.getTitle());
        projectDetailResponseDTO.setContractAmount(project.getContractAmount());
        projectDetailResponseDTO.setBorrowRate(project.getBorrowRate());
        projectDetailResponseDTO.setPenaltyRate(project.getPenaltyRate());
        projectDetailResponseDTO.setManageRate(project.getManageRate());
        projectDetailResponseDTO.setGuaranteeRate(project.getGuaranteeRate());
        projectDetailResponseDTO.setRepaymentType(project.getRepaymentType());
        projectDetailResponseDTO.setDeadline(project.getDeadline());
        projectDetailResponseDTO.setDeadlineUnit(project.getDeadlineUnit());
        projectDetailResponseDTO.setStatus(project.getStatus());
        projectDetailResponseDTO.setChannelCode(project.getChannelCode());
        projectDetailResponseDTO.setType(project.getType());
        projectDetailResponseDTO.setFromSource(project.getFromSource());
        projectDetailResponseDTO.setLoanTimes(project.getLoanTimes());
        projectDetailResponseDTO.setOrgId(project.getOrgId());
        return projectDetailResponseDTO;
    }

    private DetailCollecting getDetailCollecting(Project project) {
        DetailCollecting result = new DetailCollecting();
        // 获取已投资金额
        BigDecimal investedAmount = projectInvestOrderMapperExt.selectInvestedAmount(project.getProjectId());
        if (null == investedAmount) {
            investedAmount = BigDecimal.ZERO;
        }
        result.setInvestAmount(investedAmount);
        result.setContractAmount(project.getContractAmount());
        result.setInvestRateOfProgress(investedAmount.divide(project.getContractAmount(),
                AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN));
        if (project.getInvestEndTime() != null) {
            long nd = 1000 * 24 * 60 * 60;
            long nh = 1000 * 60 * 60;
            // 获得两个时间的毫秒时间差异
            long diff = project.getInvestEndTime().getTime() - System.currentTimeMillis();
            // 计算差多少天
            long day = diff / nd;
            // 计算差多少小时
            long hour = diff % nd / nh;

            result.setInvestEndTime(day != 0 ? (day + "天" + hour + "小时") : (hour + "小时"));
        }
        return result;
    }

    /**
     * 等额本息计算每月偿还本金和利息
     * <p>
     * 公式：每月偿还本息=〔贷款本金×月利率×(1＋月利率)＾还款月数〕÷〔(1＋月利率)＾还款月数-1〕
     *
     * @param capital     本金
     * @param monthRate   月利息
     * @param totalPeriod 总期数
     * @return
     */
    private BigDecimal getPerMonthPrincipalInterest(BigDecimal capital, BigDecimal monthRate, int totalPeriod) {
        BigDecimal dividend = capital.multiply(monthRate.multiply(new BigDecimal(1).add(monthRate).pow(totalPeriod)));
        BigDecimal divisor = (new BigDecimal(1).add(monthRate)).pow(totalPeriod).subtract(new BigDecimal(1));
        BigDecimal result = dividend.divide(divisor, AmountHandleConstant.CALCULATE_PRECISION_TWO,
                BigDecimal.ROUND_HALF_EVEN);
        return result;
    }

    /**
     * 等额本息计每月偿还利息
     * <p>
     * 公式：每月偿还利息=贷款本金×月利率×〔(1+月利率)^还款期数-(1+月利率)^(还款月序号-1)〕÷〔(1+月利率)^还款期数-1〕
     *
     * @param capital     总借款额（贷款本金）
     * @param monthRate   月利率
     * @param totalPeriod 总期数
     * @return 每月偿还利息
     */
    private Map<Integer, BigDecimal> getPerMonthInterest(BigDecimal capital, BigDecimal monthRate, int totalPeriod) {
        Map<Integer, BigDecimal> map = new HashMap<Integer, BigDecimal>();
        BigDecimal monthInterest;
        for (int i = 1; i < totalPeriod + 1; i++) {
            BigDecimal multiply = capital.multiply(monthRate);
            BigDecimal sub = (new BigDecimal(1).add(monthRate).pow(totalPeriod))
                    .subtract(new BigDecimal(1).add(monthRate).pow(i - 1));
            monthInterest = multiply.multiply(sub).divide(
                    (new BigDecimal(1).add(monthRate).pow(totalPeriod).subtract(new BigDecimal(1))),
                    MathContext.DECIMAL128);
            monthInterest = monthInterest.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO,
                    BigDecimal.ROUND_HALF_EVEN);
            map.put(i, monthInterest);
        }
        return map;
    }

    private void setDetailToBeConfirmed(QueryProjectBorrowDetailReponseDTO result, Project project) {
        Byte type = project.getType();
        if (ProjectTypeEnum.SMALL_LOAN.getValue().equals(type)
                || ProjectTypeEnum.SOCIAL_SECURITY_LOAN.getValue().equals(type)
                || ProjectTypeEnum.CREDIT_CARD_LOAN.getValue().equals(type)
                || ProjectTypeEnum.CONSUME_LOAN.getValue().equals(type)) {
            result.setDetailToBeConfirmed(getNewDetailToBeConfirmed(project));
        } else {
            result.setDetailToBeConfirmed(getDetailToBeConfirmed(project));
        }
    }

    private DetailToBeConfirmed getDetailToBeConfirmed(Project project) {
        BigDecimal contractAmount = project.getContractAmount();

        DetailToBeConfirmed result = new DetailToBeConfirmed();
        result.setContractAmount(contractAmount);
        result.setHandAmount(project.getHandAmount());
        result.setBorrowRate(project.getBorrowRate().multiply(BigDecimal.valueOf(AmountHandleConstant.HUNDRED))
                .setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN));
        result.setDeadline(project.getDeadline());
        result.setDeadlineUnit(project.getDeadlineUnit());
        result.setRepaymentType(project.getRepaymentType());
        result.setChannelCode(project.getChannelCode());
        result.setFromSource(project.getFromSource());
        result.setBizType(project.getType());
        result.setTitle(project.getTitle());

        if (ProjectFromSourceEnum.R360.getType().equals(project.getFromSource()) && project.getAuditedTime() != null) {
            Map<String, String> map = tradeConfigService.selectTradeConfigByEmuns(TradeConfigEnum.LOAN_RONG360SURETIME);
            if (map != null && map.get(TradeConfigEnum.LOAN_RONG360SURETIME.getConfigKey()) != null) {
                log.info("LOAN_RONG360SURETIME :　{}", map.get(TradeConfigEnum.LOAN_RONG360SURETIME.getConfigKey()));
                result.setConfirmEndTime(DateFormatUtils.format(
                        DateUtils.addHours(project.getAuditedTime(),
                                Integer.parseInt(map.get(TradeConfigEnum.LOAN_RONG360SURETIME.getConfigKey()))),
                        "YYYY年MM月dd日 HH:mm"));
            } else { // 默认48小时
                result.setConfirmEndTime(
                        DateFormatUtils.format(DateUtils.addHours(project.getAuditedTime(), 48), "YYYY年MM月dd日 HH:mm"));
            }
        }

        BigDecimal interest = BigDecimal.ZERO;
        BigDecimal monthRate = BigDecimal.ZERO;
        BigDecimal dayRate = BigDecimal.ZERO;

        PeriodUnitEnum periodUnit = PeriodUnitEnum.enumOf(project.getDeadlineUnit());
        switch (periodUnit) {
            case MONTH:
                // 月利率： 年化利率/12
                monthRate = project.getBorrowRate().divide(BigDecimal.valueOf(AmountHandleConstant.YEAR_OF_MONTH),
                        MathContext.DECIMAL128);
                break;

            case DAY:
                // 日利率： 年化利率/365
                dayRate = project.getBorrowRate().divide(BigDecimal.valueOf(AmountHandleConstant.YEAR_OF_DAY),
                        MathContext.DECIMAL128);
                break;

            default:
                break;
        }

        if (RepaymentTypeEnum.AVERAGE_CAPITAL_PLUS_INTEREST.getValue().equals(project.getRepaymentType())) {
            // 月利率： 年化利率/12
            result.setMonthRefundAmount(getPerMonthPrincipalInterest(contractAmount, monthRate, project.getDeadline()));

            Map<Integer, BigDecimal> interestMap = getPerMonthInterest(contractAmount, monthRate,
                    project.getDeadline());
            for (int i = 1; i < project.getDeadline() + 1; i++) {
                interest = interest.add(interestMap.get(i));
            }
        } else if (RepaymentTypeEnum.REPAY_PRINCIPAL_INTEREST_AT_TERM.getValue().equals(project.getRepaymentType())) {
            switch (periodUnit) {
                case MONTH: // 月
                    // 利息*月利率*期限
                    interest = contractAmount.multiply(monthRate).multiply(BigDecimal.valueOf(project.getDeadline()))
                            .setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
                    break;

                case DAY: // 日
                    // 利息*日利率*期限
                    interest = contractAmount.multiply(dayRate).multiply(BigDecimal.valueOf(project.getDeadline()))
                            .setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
                    break;

                default:
                    break;
            }
        } else {
            interest = contractAmount.multiply(monthRate).setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO,
                    BigDecimal.ROUND_HALF_EVEN);
        }

        // 担保服务费
        BigDecimal guaranteeFee = contractAmount.multiply(project.getGuaranteeRate())
                .setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
        result.setGuaranteeFee(guaranteeFee);//

        // 平台管理费
        BigDecimal manageFeeTotal = project.getContractAmount().multiply(project.getManageRate())
                .setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
        result.setManagementFee(manageFeeTotal);

        result.setInterest(interest);

        result.setRefundTotalAmount(contractAmount.add(result.getInterest()).add(guaranteeFee).add(manageFeeTotal));

        return result;
    }

    private DetailToBeConfirmed getNewDetailToBeConfirmed(Project project) {
        String userId = project.getBorrowUserId();
        Long projectId = project.getProjectId();
        Byte type = project.getType();
        Byte teProjectFlag = project.getTeProjectFlag();
        BigDecimal applyAmount = project.getHandAmount(); //调整前申请金额
        Integer applyDeadline = project.getDeadline(); //调整前申请期限

        BigDecimal auditAmount = null;
        Integer auditDeadline = null;

        boolean teGet = false;
        if(TeProjectFlagEnum.YES.getValue().equals(teProjectFlag)){
            ProjectCreditAmount projectCreditAmount = projectCreditAmountMapper.selectByPrimaryKey(projectId);
            log.info("getNewDetailToBeConfirmed.projectCreditAmount={}", JSON.toJSONString(projectCreditAmount));

            if(projectCreditAmount!=null || TeProjectFlagEnum.YES.getValue().equals(projectCreditAmount.getTeProjectFlag())){
                auditAmount = projectCreditAmount.getCreditAmount();
                auditDeadline = project.getDeadline();
                teGet = true;
            }
        }

        if(!teGet){
            AuditAdditionalInfo auditAdditionalInfo = auditAdditionalInfoMapper.selectByProjectId(projectId);
            if(auditAdditionalInfo!=null) {
                log.info("getNewDetailToBeConfirmed.auditAdditionalInfo={}", JSON.toJSONString(auditAdditionalInfo));
                auditAmount = auditAdditionalInfo.getAuditAmount();
                auditDeadline = Integer.valueOf(auditAdditionalInfo.getAuditDeadline());
            }else{
                //自动审核通过-待确认，非人工后台审核通过
                auditAmount = Optional.ofNullable(projectCreditAmountMapper.selectByPrimaryKey(projectId)).map(ProjectCreditAmount::getCreditAmount).orElse(BigDecimal.ZERO);
                auditDeadline = project.getDeadline();
            }
        }

        ProjectTypeEnum projectTypeEnum = ProjectTypeEnum.getEnum(type);
        log.info("getNewDetailToBeConfirmed.userId={},projectTypeEnum={}", userId, JSON.toJSONString(projectTypeEnum));
        ProjectRateConfig projectRateConfig = loanConfigService.selectRateConfigByDeadlineTypeEnum(auditDeadline, projectTypeEnum);
        log.info("getNewDetailToBeConfirmed.userId={},projectRateConfig={}", userId, JSON.toJSONString(projectRateConfig));

        project.setContractAmount(auditAmount);
        project.setHandAmount(auditAmount);
        project.setBorrowRate(projectRateConfig.getBorrowInterestRate());
        project.setRepaymentType(projectRateConfig.getRepaymentMode());
        project.setDeadline(Integer.valueOf(auditDeadline));
        project.setGuaranteeRate(projectRateConfig.getGuaranteeServiceFeeRate());
        project.setManageRate(projectRateConfig.getPlatformManageFeeRate());

        DetailToBeConfirmed result = this.getDetailToBeConfirmed(project);

        result.setNoticeContent(this.getPassNoticeContent(project));
        result.setBorrowInterestRate(projectRateConfig.getBorrowInterestRate());
        result.setGuaranteeServiceFeeRate(projectRateConfig.getGuaranteeServiceFeeRate());
        result.setPlatformManageFeeRate(projectRateConfig.getPlatformManageFeeRate());
        result.setApplyAmount(applyAmount);
        result.setApplyDeadline(String.valueOf(applyDeadline));

        LoanBusinessInfo loanBusinessInfo = loanConfigService.selectBusinessInfo(projectTypeEnum);
        if (loanBusinessInfo != null) {
            result.setOverDueFee(loanBusinessInfo.getOverDueFee());
        }

        return result;
    }

    /**
     * 查询借款详情
     *
     * @param projectId
     * @return
     */
    public QueryProjectBorrowDetailReponseDTO queryProjectBorrowDetail(Long projectId, String userId) {
        Assert.notNull(projectId, "queryProjectBorrowDetail projectId is null");
        Assert.notNull(userId, "queryProjectBorrowDetail userId is null");

        QueryProjectBorrowDetailReponseDTO result = new QueryProjectBorrowDetailReponseDTO();

        Project project = projectMapperExt.selectByPrimaryKey(projectId);
        if (project == null) {
            throw new BizException("TRD20001");
        }
        result.setType(project.getType());
        result.setTeProjectFlag(project.getTeProjectFlag());

        // 是否显示借款凭证
        LoanVoucherAudit loanVoucherAudit = loanVoucherAuditMapper.selectByUserIdProjectId(project.getBorrowUserId(), project.getProjectId());
        if (loanVoucherAudit != null) {
            result.setLoanVoucherAuditStatus(loanVoucherAudit.getAuditStatus());
        }
        result.setProjectId(projectId);

        ProjectDisplayStatusEnum disStatus = this.getDisplayStatus(project.getStatus(), project.getSubStatus());
        result.setDisStatus(disStatus.getStatus());
        result.setSubStatus(project.getSubStatus());
        switch (disStatus) {
            case CHECKING:
                result.setDetailChecking(new DetailChecking());
                break;
            case MISCARRY:
                ProjectFlowed projectFlowed = projectFlowedMapper.selectByPrimaryKey(projectId);
                DetailMiscarry detailMiscarry = new DetailMiscarry();
                if (projectFlowed != null) {
                    detailMiscarry.setMiscarryDisplay(projectFlowed.getFlowedReason());
                    detailMiscarry.setMiscarryTime(
                            DateFormatUtils.format(projectFlowed.getCreateTime(), DatePatternConstant.MM_DD_HH_MM));
                    // 是否显示第三方渠道,只有借款人自己取消的标的不显示
                    detailMiscarry.setShowThirdChannel(projectFlowed.getIsSystemFlowed()
                            || (!StringUtils.equals(project.getBorrowUserId(), projectFlowed.getUserId())));
                }
                result.setDetailMiscarry(detailMiscarry);
                break;
            case BACK:
                setDetailBack(result, project);
                break;
            case TO_BE_CONFIRMED:
                setDetailToBeConfirmed(result, project);
                break;
            case COLLECTING:
                result.setDetailCollecting(getDetailCollecting(project));
                break;
            case REPAYING:
                result.setDetailRepaying(getDetailBadDebt(project, disStatus));
                break;
            case OVERDUE_REPAYING:
                result.setDetailOverdueRepaying(getDetailBadDebt(project, disStatus));
                break;
            case BAD_DEBT:
                result.setDetailBadDebt(getDetailBadDebt(project, disStatus));
                break;
            case FINISH:
                result.setDetailFinish(new DetailFinish());
                break;
            case BAD_DEBT_FINISH:
                result.setDetailBadDebtFinish(new DetailBadDebtFinish());
                break;

        }

        return result;
    }

    //获取详情页面通知内容，比如：请您在XXXX年XX月XX日24:00前确认，过期借款申请将失效哦
    private String getPassNoticeContent(Project project) {
        ProjectTypeEnum projectTypeEnum = ProjectTypeEnum.getEnum(project.getType());
        LoanBusinessConfig loanBusinessConfig = loanConfigService.selectBusinessConfig(projectTypeEnum);
        if (loanBusinessConfig == null) {
            return "";
        }
        Short confirmMaxDays = loanBusinessConfig.getPassConfirmMaxDays();
        if (confirmMaxDays == null) {
            log.info("getNoticeContent获取确认时间配置为空！！！");
            return "";
        }

        String dateString = FastDateFormat.getInstance("yyyy年MM月dd日").format(com.niiwoo.tripod.base.utils.DateUtils.addDate(project.getUpdateTime(), Calendar.DAY_OF_YEAR, Integer.valueOf(confirmMaxDays)));

        return String.format("请您在%s24:00前确认，过期借款申请将失效哦。", dateString);
    }

    //获取详情页面通知内容，比如：请您在XXXX年XX月XX日24:00前确认，过期借款申请将失效哦
    private String getBackNoticeContent(Project project) {
        ProjectTypeEnum projectTypeEnum = ProjectTypeEnum.getEnum(project.getType());
        LoanBusinessConfig loanBusinessConfig = loanConfigService.selectBusinessConfig(projectTypeEnum);
        if (loanBusinessConfig == null) {
            return "";
        }
        Short confirmMaxDays = loanBusinessConfig.getReturnConfirmMaxDays();
        if (confirmMaxDays == null) {
            log.info("getNoticeContent获取确认时间配置为空！！！");
            return "";
        }

        String dateString = FastDateFormat.getInstance("yyyy年MM月dd日").format(com.niiwoo.tripod.base.utils.DateUtils.addDate(project.getUpdateTime(), Calendar.DAY_OF_YEAR, Integer.valueOf(confirmMaxDays)));

        return String.format("请您在%s24:00前确认，过期借款申请将失效哦。", dateString);
    }

    private void setDetailBack(QueryProjectBorrowDetailReponseDTO result, Project project) {
        Byte type = project.getType();
        if (ProjectTypeEnum.SMALL_LOAN.getValue().equals(type)
                || ProjectTypeEnum.SOCIAL_SECURITY_LOAN.getValue().equals(type)
                || ProjectTypeEnum.CREDIT_CARD_LOAN.getValue().equals(type)
                || ProjectTypeEnum.CONSUME_LOAN.getValue().equals(type)) {
            result.setNewDetailBack(this.getNewDetailBack(project));
        } else {
            result.setDetailBack(this.getDetailBack(project));
        }
    }

    // 获取回退原因
    private DetailBack getDetailBack(Project project) {
        String userId = project.getBorrowUserId();
        Long projectId = project.getProjectId();
        Integer subStatus = project.getSubStatus();

        DetailBack detailBack = new DetailBack();

        try {
            // 如果是人工审核回退
            if (ProjectSubStatusEnum.CHECKING_BACK.getSubStatus() == subStatus) {
                ProjectAuditDecision projectAuditDecision = projectAuditDecisionMapper.selectForBackProject(userId,
                        projectId);
                log.info("MyLoanLocalService.getDetailBack userId={},projectAuditDecision={}", userId,
                        JSON.toJSONString(projectAuditDecision));
                Optional.ofNullable(projectAuditDecision).ifPresent(d -> {
                    detailBack.setReasonList(this.getBackReasonList(d.getAuditReason()));
                    detailBack.setProcessScheme(d.getProcessScheme());
                });
            } else {// 如果是自动审核回退
                detailBack.setReasonList(Arrays.asList(ProjectSubStatusEnum.enumOf(subStatus).getDesc()));
                Optional.ofNullable(ProjectSubStatusEnum.CHECKING_BACK_PHONEOPERATOR_TIMEOUT.getSubStatus() == subStatus
                        ? ProcessSchemeEnum.UPDATE_CREDIT_INFO
                        : ProcessSchemeEnum.UPDATE_LOAN_INFO).ifPresent(processSchemeEnum -> {
                    detailBack.setProcessScheme(processSchemeEnum.getValue());
                });
            }
        } catch (Exception e) {
            log.error("MyLoanLocalService.getDetailBack error", e);
        }
        return detailBack;
    }


    public NewDetailBack getNewDetailBack(Project project) {
        String userId = project.getBorrowUserId();
        Long projectId = project.getProjectId();
        Integer subStatus = project.getSubStatus();

        NewDetailBack detailBack = getNewDetailBackForBackMaterial(project);
        if (ProjectSubStatusEnum.CHECKING_BACK_PHONEOPERATOR_TIMEOUT.getSubStatus() == subStatus
                || ProjectSubStatusEnum.CHECKING_BACK_ADDRESSLIST_TIMEOUT.getSubStatus() == subStatus) {
            ReturnProjectRecord returnProjectRecord = returnProjectRecordMapperExt.selectLatelyRecordByProjectId(userId, projectId);
            log.info("getNewDetailBack.userId={},projectId={},returnProjectRecord={}", userId, project, JSON.toJSON(returnProjectRecord));
            List<String> reasonList = (returnProjectRecord == null ? Arrays.asList(ProjectSubStatusEnum.enumOf(subStatus).getDesc()) : Arrays.asList(returnProjectRecord.getReturnReason()));
            detailBack.setReasonList(reasonList);
        } else {
            detailBack.setReasonList(this.getBackReasonList(userId, projectId));
        }
        detailBack.setNoticeContent(this.getBackNoticeContent(project));
        return detailBack;
    }

    //退回资料详情查询
    public NewDetailBack getNewDetailBackForBackMaterial(Project project) {
        NewDetailBack detailBack = new NewDetailBack();

        detailBack.setType(project.getType());
        detailBack.setLoanTerm(project.getDeadline());
        detailBack.setHandAmount(project.getHandAmount());
        detailBack.setLoanUsage(project.getTitle());

        return detailBack;
    }

    private List<String> getBackReasonList(String userId, Long projectId) {
        ProjectAuditDecision projectAuditDecision = projectAuditDecisionMapper.selectForBackProject(userId, projectId);

        log.info("getBackReasonList.userId={},projectAuditDecision={}", userId, JSON.toJSONString(projectAuditDecision));

        if (projectAuditDecision == null) {
            return null;
        }

        String auditReason = projectAuditDecision.getAuditReason();
        if (StringUtils.isEmpty(auditReason)) {
            return null;
        }
        String[] auditReasonArray = auditReason.split("\\|");
        return projectAuditConfigMapperExt.selectAuditReasonNameByReasonCodeList(Arrays.asList(auditReasonArray));
    }

    private List<String> getBackReasonList(String auditReason) {
        if (StringUtils.isEmpty(auditReason)) {
            return null;
        }
        String[] auditReasonArray = auditReason.split("\\|");
        return projectAuditConfigMapperExt.selectAuditReasonNameByReasonCodeList(Arrays.asList(auditReasonArray));
    }

    /**
     * 查询还款安排
     *
     * @param projectId
     * @return
     */
    public QueryRepaymentPlanResponseDTO queryRepaymentPlan(Long projectId, String userId) {
        Assert.notNull(projectId, "queryRepaymentPlan projectId is null");
        // 标的信息
        Project project = Optional.ofNullable(projectMapperExt.selectByPrimaryKey(projectId)).orElseThrow(() -> new BizException("TRD20001"));

        // 还款计划
        List<ProjectBorrowerPlanNew> projectBorrowerPlanNewList = Optional.ofNullable(projectBorrowerPlanNewMapperExt.selectByProjectId(projectId))
                .orElseThrow(() -> new BizException("TRD20005"));

        // 接口返回还款详情列表
        List<ProjectBorrowerPlanReponseDTO> borrowerPlanReponseDTOList = Lists.newArrayList();

        // 记录提前结清当期信息
        ProjectBorrowerPlanReponseDTO earlySettlementPlan = null;

        BigDecimal earlySettlementCapital = BigDecimal.ZERO; // 提前结清本金
        BigDecimal earlySettlementInterest = BigDecimal.ZERO; // 提前结清利息
        BigDecimal earlySettlementPenaltyFee = BigDecimal.ZERO; // 提前结清罚息
        BigDecimal earlySettlementManagementFee = BigDecimal.ZERO; // 提前结清平台管理费
        BigDecimal earlySettlementGuaranteeFee = BigDecimal.ZERO; // 提前结清担保服务费

        // 是否提前结清
        boolean isEarlySettlement = false;

        for (ProjectBorrowerPlanNew projectBorrowerPlanNew : projectBorrowerPlanNewList) {
            // 当期费用详情
            ProjectBorrowerPlanNewDetailDTO projectBorrowerPlanNewDetailDTO = refundCommonService.bulidProjectBorrowerPlanNewAmount(projectBorrowerPlanNew.getId());

            // 提前结清后续（除了提前结清当期）只做金额统计
            if (isEarlySettlement) {
                earlySettlementCapital = earlySettlementCapital.add(projectBorrowerPlanNewDetailDTO.getRefundedCapital());
                earlySettlementInterest = earlySettlementInterest.add(projectBorrowerPlanNewDetailDTO.getRefundedInterest());
                earlySettlementPenaltyFee = earlySettlementPenaltyFee.add(projectBorrowerPlanNewDetailDTO.getRefundedPenaltyFee());
                earlySettlementManagementFee = earlySettlementManagementFee.add(projectBorrowerPlanNewDetailDTO.getRefundedManagementFee());
                earlySettlementGuaranteeFee = earlySettlementGuaranteeFee.add(projectBorrowerPlanNewDetailDTO.getRefundedGuaranteeFee());
            } else {
                ProjectBorrowerPlanReponseDTO borrowerPlanReponseDTO = new ProjectBorrowerPlanReponseDTO();

                borrowerPlanReponseDTO.setCurrentPeriod(projectBorrowerPlanNew.getPeriod());
                borrowerPlanReponseDTO.setTotalPeriod(projectBorrowerPlanNew.getTotalPeriod());
                borrowerPlanReponseDTO.setRefundDate(DateFormatUtils.format(projectBorrowerPlanNew.getRefundDate(), DatePatternConstant.YYYY_MM_DD));
                borrowerPlanReponseDTO.setRefundStatus(projectBorrowerPlanNew.getStatus());

                // 费用信息
                borrowerPlanReponseDTO.setCapital(projectBorrowerPlanNewDetailDTO.getCapital());
                borrowerPlanReponseDTO.setInterest(projectBorrowerPlanNewDetailDTO.getInterest());
                borrowerPlanReponseDTO.setPenaltyFee(projectBorrowerPlanNewDetailDTO.getPenaltyFee());
                borrowerPlanReponseDTO.setManagementFee(projectBorrowerPlanNewDetailDTO.getManagementFee());
                borrowerPlanReponseDTO.setGuaranteeFee(projectBorrowerPlanNewDetailDTO.getGuaranteeFee());

                // 逾期与坏帐
                BorrowerPlanOverdueDTO borrowerPlanOverdueDTO = refundCommonService.getBorrowerPlanOverdueInfo(projectBorrowerPlanNew, project);
                borrowerPlanReponseDTO.setIsOverdue(borrowerPlanOverdueDTO.getIsOverdue());
                borrowerPlanReponseDTO.setIsBadDebt(borrowerPlanOverdueDTO.getIsBadloan());
                borrowerPlanReponseDTO.setOverdueDay(borrowerPlanOverdueDTO.getOverdueDay());
                if (ChannelCodeEnum.KAOLA.getChanelCode().equalsIgnoreCase(project.getChannelCode())) {
                    borrowerPlanReponseDTO.setOverdueDay(kaoLaLiCaiRepaymentService.getKaolaOverdueDays(projectBorrowerPlanNew.getRefundDate()));
                }
                if (borrowerPlanOverdueDTO.getIsOverdue()) {
                    borrowerPlanReponseDTO.setOverdueDesc("逾期" + borrowerPlanOverdueDTO.getOverdueDay() + "天，罚息：￥" + projectBorrowerPlanNewDetailDTO.getPenaltyFee());
                }

                // 提前结清
                if (BorrowerPlanRefundStatusEnum.OVER_DEBT_REPAYMENT.getCode().equals(projectBorrowerPlanNew.getStatus())) {
                    isEarlySettlement = true;
                }
                borrowerPlanReponseDTO.setIsEarlySettlement(isEarlySettlement);

                // 提前结清当期
                if (isEarlySettlement) {
                    earlySettlementPlan = borrowerPlanReponseDTO;

                    borrowerPlanReponseDTO.setRefundDate(DateFormatUtils.format(projectBorrowerPlanNew.getOverDate(), DatePatternConstant.YYYY_MM_DD));
                    earlySettlementCapital = earlySettlementCapital.add(projectBorrowerPlanNewDetailDTO.getRefundedCapital());
                    earlySettlementInterest = earlySettlementInterest.add(projectBorrowerPlanNewDetailDTO.getRefundedInterest());
                    earlySettlementPenaltyFee = earlySettlementPenaltyFee.add(projectBorrowerPlanNewDetailDTO.getRefundedPenaltyFee());
                    earlySettlementManagementFee = earlySettlementManagementFee.add(projectBorrowerPlanNewDetailDTO.getRefundedManagementFee());
                    earlySettlementGuaranteeFee = earlySettlementGuaranteeFee.add(projectBorrowerPlanNewDetailDTO.getRefundedGuaranteeFee());
                } else {
                    borrowerPlanReponseDTOList.add(borrowerPlanReponseDTO);
                }
            }
        }

        // 重置提前结清当前的费用信息，并添加到还款计划列表
        if (isEarlySettlement) {
            earlySettlementPlan.setCapital(earlySettlementCapital);
            earlySettlementPlan.setInterest(earlySettlementInterest);
            earlySettlementPlan.setPenaltyFee(earlySettlementPenaltyFee);
            earlySettlementPlan.setManagementFee(earlySettlementManagementFee);
            earlySettlementPlan.setGuaranteeFee(earlySettlementGuaranteeFee);
            borrowerPlanReponseDTOList.add(earlySettlementPlan);
        }

        // 返回对象
        QueryRepaymentPlanResponseDTO queryRepaymentPlanResponseDTO = new QueryRepaymentPlanResponseDTO();
        queryRepaymentPlanResponseDTO.setRepaymentType(project.getRepaymentType());
        queryRepaymentPlanResponseDTO.setBizType(project.getType());
        queryRepaymentPlanResponseDTO.setBorrowerPlanReponseDTOList(borrowerPlanReponseDTOList);

        return queryRepaymentPlanResponseDTO;
    }

    /**
     * 查询还款记录
     *
     * @param projectId
     * @return
     */
    public QueryProjectDynamicReponseDTO queryProjectDynamic(Long projectId, String userId) {
        Assert.notNull(projectId, "queryProjectDynamic projectId is null");
        Assert.notNull(projectId, "queryProjectDynamic userId is null");

        QueryProjectDynamicReponseDTO result = new QueryProjectDynamicReponseDTO();
        List<ProjectDynamicReponseDTO> projectDynamicReponseDTOList = new ArrayList<ProjectDynamicReponseDTO>();

        List<ProjectDynamic> projectDynamicList = dynamicMapperExt
                .queryProjectRepaymentDynamicListCreateTimeDescByProjectId(projectId);
        if (projectDynamicList != null) {
            for (ProjectDynamic projectDynamic : projectDynamicList) {
                if (projectDynamic != null) {
                    ProjectDynamicReponseDTO projectDynamicReponseDTO = new ProjectDynamicReponseDTO();
                    projectDynamicReponseDTO.setId(projectDynamic.getId());
                    projectDynamicReponseDTO.setProjectId(projectDynamic.getProjectId());
                    projectDynamicReponseDTO.setUserId(projectDynamic.getUserId());
                    projectDynamicReponseDTO.setRelationId(projectDynamic.getRelationId());
                    projectDynamicReponseDTO.setType(projectDynamic.getType());
                    projectDynamicReponseDTO.setDescription(projectDynamic.getDescription());
                    projectDynamicReponseDTO.setCreateTime(DateFormatUtils.format(projectDynamic.getCreateTime(),
                            DatePatternConstant.YYYY_MM_DD_HH_MM_SS));

                    projectDynamicReponseDTOList.add(projectDynamicReponseDTO);
                }
            }
        }
        result.setProjectId(projectId);
        result.setProjectDynamicReponseDTOList(projectDynamicReponseDTOList);
        return result;
    }

    /**
     * 查询提前还款待还金额
     * 
     * @param projectId
     * @param userId
     * @return
     */
    public QueryFullAmountRepaymentReponseDTO queryFullRepayAmount(Long projectId, String userId) {
        Assert.notNull(projectId, "queryRepaymentPlan projectId is null");
        Assert.notNull(userId, "queryRepaymentPlan userId is null");
        
        // 标的信息
        Project project = Optional.ofNullable(projectMapperExt.selectByPrimaryKey(projectId)).orElseThrow(() -> new BizException("TRD20001"));

        // 还款摘要
        ProjectBorrowerSummary projectBorrowerSummary = projectBorrowerSummaryMapperExt.selectByPrimaryKey(projectId);

        // 坏帐不可以提前还款
        if (RepayStatusEnum.BADLOANS.getCode().equals(projectBorrowerSummary.getRepayStatus())) {
            throw new BizException("TRD20007");
        }

        QueryFullAmountRepaymentReponseDTO queryFullAmountRepaymentReponseDTO = new QueryFullAmountRepaymentReponseDTO();

        // 调用计算服务获取当前应还金额
        RefundStateDTO refundStateDTO = feeCalcForRefundService.caculateAmountRepaymentForAPP(project.getProjectId(), RefundTypeEnum.OVERDEPT);

        queryFullAmountRepaymentReponseDTO.setRepaymentCapitalTotal(refundStateDTO.getCapital());
        queryFullAmountRepaymentReponseDTO.setCurrentPeriodInterest(refundStateDTO.getInterest());
        queryFullAmountRepaymentReponseDTO.setRepaymentManagementFeeTotal(refundStateDTO.getManageFee());
        queryFullAmountRepaymentReponseDTO.setRepaymentGuaranteeFeeTotal(refundStateDTO.getGuaranteeFee());
        queryFullAmountRepaymentReponseDTO.setRepaymentConsultingFeeTotal(refundStateDTO.getConsultingFee());
        queryFullAmountRepaymentReponseDTO.setEconomizeAmount(refundStateDTO.getReducedFee());
        queryFullAmountRepaymentReponseDTO.setRepaymentPenaltyTotal(refundStateDTO.getPenaltyFee());
        queryFullAmountRepaymentReponseDTO.setRepaymentTotalAmount(refundStateDTO.getAmount());
        Integer overdueDay;
        if (ChannelCodeEnum.KAOLA.getChanelCode().equalsIgnoreCase(projectBorrowerSummary.getChannelCode())) {
            overdueDay = kaoLaLiCaiRepaymentService.getKaolaOverdueDays(projectBorrowerSummary.getRefundDate());
        } else {
            overdueDay = RepaymentUtil.getOverdueDay(projectBorrowerSummary.getRefundDate(), commonLocalService.getCurrentDate());
        }
        if (overdueDay > 0) {
            queryFullAmountRepaymentReponseDTO.setOverDueInfo("第【" + projectBorrowerSummary.getCurrentPeriod() + "/" + projectBorrowerSummary.getTotalPeriod()
                    + "期】逾期" + overdueDay + "天未还，罚息：" + refundStateDTO.getPenaltyFee() + " 元");
        }

        // 验证是否可以还款
        queryFullAmountRepaymentReponseDTO.setCanRefund(refundCommonService.checkCanRefund(projectId).getCode());

        return queryFullAmountRepaymentReponseDTO;        
    }

    public OrgImmediateRepaymentResponseDTO queryOrgImmediateRepayment(String userId, String orgId){
        log.info("queryImmediateRepaymentList userId:{}, orgId:{}", userId, orgId);
        OrgImmediateRepaymentResponseDTO result = new OrgImmediateRepaymentResponseDTO();
        List<Project> projectList = projectMapperExt.selectProjectByUserIdAndOrgId(userId, orgId);
        if(!projectList.isEmpty()){
            for (Project project: projectList) {
                if(ProjectStatusEnum.FINISH.getStatus().equals(project.getStatus())) {
                    result.setStatus(Byte.valueOf("3"));
                    break;
                }
            }

            for (Project project: projectList) {
                if(ProjectStatusEnum.CHECKING.getStatus().equals(project.getStatus()) || ProjectStatusEnum.COLLECTING.getStatus().equals(project.getStatus())
                        || ProjectStatusEnum.MISCARRY.getStatus().equals(project.getStatus())) {
                    result.setStatus(Byte.valueOf("2"));
                    break;
                }
            }

            Long projectId = null;
            boolean flag = false;

            for (Project project: projectList) {
                if(ProjectStatusEnum.REPAYING.getStatus().equals(project.getStatus())) {
                    try {
                        refundLocalService.checkRepaymentByProjectId(project.getProjectId());
                        result.setStatus(Byte.valueOf("0"));
                        flag = true;
                        projectId = project.getProjectId();

                        break;
                    }catch (BizException e){
                        result.setStatus(Byte.valueOf("4"));
                        projectId = project.getProjectId();
                        log.info("不可还款 projectId:{}",project.getProjectId(),e);
                    }
                }
            }

            if (flag) {
                MyProjectRequestDTO dto = new MyProjectRequestDTO();
                dto.setProjectId(projectId);
                ImmediateRepaymentResponseDTO immediateRepaymentResponseDTO = this.queryImmediateRepayment(dto);
                BeanUtils.copyProperties(immediateRepaymentResponseDTO, result);
            }

            if(Byte.valueOf("4").equals(result.getStatus())){
                ProjectBorrowerSummary projectBorrowerSummary = projectBorrowerSummaryMapperExt.selectByPrimaryKey(projectId);
                Integer currentPeriod = projectBorrowerSummary.getCurrentPeriod();
                log.info("当期已还 projectId:{}，nextPeriod:{}", projectId, currentPeriod);
                List<Integer> periods = new ArrayList<>();
                periods.add(currentPeriod);
                RefundStateDTO refundStateDTO = feeCalcForRefundService.caculateAmountByPeriods(projectId, periods);
                result.setNextPeriodAmount(refundStateDTO.getAmount());
                result.setProjectId(projectId);
            }
        } else {
            result.setStatus(Byte.valueOf("2"));
        }
        log.info("queryImmediateRepaymentList result:{}", JSON.toJSON(result));

        return result;
    }

    /**
     * 获取立即还款待还金额
     * 
     * @param dto
     * @return
     */
    public ImmediateRepaymentResponseDTO queryImmediateRepayment(MyProjectRequestDTO dto) {
    	Long projectId = dto.getProjectId();
    	
        Assert.notNull(dto.getProjectId(), "queryImmediateRepayment projectId is null");
    	
        ProjectBorrowerSummary projectBorrowerSummary = projectBorrowerSummaryMapperExt.selectByPrimaryKey(projectId);

        Project project = projectMapperExt.selectByPrimaryKey(projectId);

        // 计算当前应还金额
        RefundStateDTO refundStateDTO = feeCalcForRefundService.caculateAmountRepaymentForAPP(project.getProjectId(), RefundTypeEnum.IMMEDIATELY);

        ImmediateRepaymentResponseDTO immediateRepaymentResponseDTO = new ImmediateRepaymentResponseDTO();
        immediateRepaymentResponseDTO.setAmount(refundStateDTO.getAmount());
        immediateRepaymentResponseDTO.setCurrentPeriod(projectBorrowerSummary.getCurrentPeriod());
        immediateRepaymentResponseDTO.setTotalPeriod(projectBorrowerSummary.getTotalPeriod());
        immediateRepaymentResponseDTO.setRefundDate(projectBorrowerSummary.getRefundDate());
        immediateRepaymentResponseDTO.setProjectId(projectId);
        immediateRepaymentResponseDTO.setRefundStatus(BorrowerPlanRefundStatusEnum.NON_REPAYMENT.getCode());
        if (ChannelCodeEnum.KAOLA.getChanelCode().equalsIgnoreCase(projectBorrowerSummary.getChannelCode())) {
            immediateRepaymentResponseDTO.setOverdueDays(kaoLaLiCaiRepaymentService.getKaolaOverdueDays(projectBorrowerSummary.getRefundDate()));
        } else {
            immediateRepaymentResponseDTO.setOverdueDays(RepaymentUtil.getOverdueDay(projectBorrowerSummary.getRefundDate(), commonLocalService.getCurrentDate()));
        }
        immediateRepaymentResponseDTO.setRepayStatus(projectBorrowerSummary.getRepayStatus());

        // 判断当前标是否有正在执行还款操作的记录
        if (ChannelCodeEnum.KAOLA.getChanelCode().equalsIgnoreCase(project.getChannelCode())) {
            immediateRepaymentResponseDTO.setCanRefund(kaoLaLiCaiRepayOrderService.isProcessing(projectId).getCode());
        } else {
            immediateRepaymentResponseDTO.setCanRefund(refundCommonService.checkCanRefund(projectId).getCode());
        }
        return immediateRepaymentResponseDTO;
    }

    /**
     * 回款计划-查询回款日期与当日回款总本金总利息
     * @param dto dto
     * @return PageResponseDTO
     */
    public PageResponseDTO<BackToArticleByDayResponseDTO> backToArticleDay(MyloanRequestDTO dto) {
        log.info("backToArticleDay：MyLoanRequestDTO={}", JSON.toJSONString(dto));
        PageResponseDTO<BackToArticleByDayResponseDTO> result = new PageResponseDTO<>();
        if(Objects.isNull(dto.getStartTime()) && Objects.isNull(dto.getEndTime())){
            Integer count = projectInvestorPlanMapperExt.listBackToArticleDayCount(dto.getUserId());
            result.setTotalCount(count);
            result.measureTotalPage(count, dto.getPageSize());
            if (count <= 0) {
                result.setItems(new ArrayList<>());
                return result;
            }
            List<BackToArticleByDayResponseDTO> list = projectInvestorPlanMapperExt.listBackToArticleDayByPage(dto.getUserId(), dto);
            result.setItems(list);
        }else {
            List<BackToArticleByDayResponseDTO> list = new ArrayList<>();
            BackToArticleByDayResponseDTO responseDTO = new BackToArticleByDayResponseDTO();
            DateTime toDay = new DateTime();
            // 全部总金额
            responseDTO.setAllTotalAmount(Optional
                    .ofNullable(projectInvestorPlanMapperExt.receivableAmountStatistical(dto.getUserId(), toDay.toDate(), null)).orElse(BigDecimal.ZERO));
            // 一月总金额
            responseDTO.setJanuaryTotalAmount(Optional
                    .ofNullable(projectInvestorPlanMapperExt.receivableAmountStatistical(dto.getUserId(), toDay.toDate(), toDay.plusMonths(1).toDate())).orElse(BigDecimal.ZERO));
            // 三月总金额
            responseDTO.setMarchTotalAmount(Optional
                    .ofNullable(projectInvestorPlanMapperExt.receivableAmountStatistical(dto.getUserId(), toDay.toDate(), toDay.plusMonths(3).toDate())).orElse(BigDecimal.ZERO));
            // 半年总金额
            responseDTO.setHalfYearTotalAmount(Optional
                    .ofNullable(projectInvestorPlanMapperExt.receivableAmountStatistical(dto.getUserId(), toDay.toDate(), toDay.plusMonths(6).toDate())).orElse(BigDecimal.ZERO));

            Integer count = projectInvestorPlanMapperExt.queryReceivableListByDateCount(dto);
            result.setTotalCount(count);
            result.measureTotalPage(count, dto.getPageSize());
            if (count <= 0) {
                list.add(responseDTO);
                result.setItems(list);
                return result;
            }

            List<BackToArticleDetails> backToArticleDetailsList = projectInvestorPlanMapperExt.queryReceivableListByDate(dto);
            responseDTO.setDueInTotalReward(BigDecimal.ZERO);
            responseDTO.setDueInTotalCapital(BigDecimal.ZERO);
            responseDTO.setDueInTotalInterest(BigDecimal.ZERO);
            responseDTO.setDetails(backToArticleDetailsList);
            dto.setPageNumber(1);
            dto.setPageSize(99999);
            List<BackToArticleDetails> allBackToArticleDetailsList = projectInvestorPlanMapperExt.queryReceivableListByDate(dto);
            allBackToArticleDetailsList.forEach(d -> {
                responseDTO.setDueInTotalCapital(d.getTotalCapital().add(responseDTO.getDueInTotalCapital()));
                responseDTO.setDueInTotalInterest(d.getTotalInterest().add(responseDTO.getDueInTotalInterest()));
            });
            responseDTO.setDueInTotalNumber(allBackToArticleDetailsList.size());
            BackToArticleDetails details = allBackToArticleDetailsList.get(0);
            responseDTO.setRecentPaybackDate(details.getReceivedDate());
            responseDTO.setRecentReceivableNumber(details.getReceivableNumber());
            responseDTO.setRecentReceivableTotal(details.getTotalCapital().add(details.getTotalInterest()).add(details.getTotalReward()));
            responseDTO.setDueInTotalAmount(responseDTO.getDueInTotalCapital().add(responseDTO.getDueInTotalInterest()).add(responseDTO.getDueInTotalReward()));
            list.add(responseDTO);
            result.setItems(list);
        }
        return result;
    }

    /**
     * 回款计划-按日查看回款计划明细
     * @param dto dto
     * @param receivedDate receivedDate
     * @return PageResponseDTO
     */
    public PageResponseDTO<InvestorPlanDTO> backToArticleDayByDay(MyloanRequestDTO dto, Date receivedDate) {
        PageResponseDTO<InvestorPlanDTO> result = new PageResponseDTO<>();

        Integer count = projectInvestorPlanMapperExt.listBackToArticleByDayCount(dto.getUserId(), receivedDate);
        if (count <= 0) {
            result.setItems(new ArrayList<>());
            return result;
        }

        List<InvestorPlanDTO> list = projectInvestorPlanMapperExt.listBackToArticleByDayAndPage(dto, receivedDate);

        // 投资类型：1-原始标，2-债转标
        Set<Long> projectIds = new HashSet<>();
        Map<Long, ProjectContract> projectContractMap = new HashMap<>();
        list.forEach( p-> {
            if (Byte.valueOf("1").equals(p.getInvestType())) {
                projectIds.add(p.getProjectId());
            }
        });

        if(projectIds.size() > 0){
            List<ProjectContract> contracts = projectContractMapperExt.queryFastLoanContractByProjectIdSet(projectIds);
            contracts.forEach(contract-> projectContractMap.put(contract.getProjectId(), contract));
        }

        list.forEach( investorPlanDTO -> {
            investorPlanDTO.setH5InvestDetailUrl(dto.getH5InvestDetailUrl() + investorPlanDTO.getInvestOrderId());
            investorPlanDTO.setExpectReceivableAmount(investorPlanDTO.getCapital().add(investorPlanDTO.getInterest()).add(investorPlanDTO.getReward()));

            if (Byte.valueOf("1").equals( investorPlanDTO.getInvestType()) && projectContractMap.get(investorPlanDTO.getProjectId()) != null) {
                investorPlanDTO.setToViewContractUrl(projectContractMap.get(investorPlanDTO.getProjectId()).getViewUrl());
                investorPlanDTO.setDownloadContractUrl(projectContractMap.get(investorPlanDTO.getProjectId()).getDownloadUrl());
            }
        });

        result.setItems(list);
        result.setTotalCount(count);
        result.measureTotalPage(count, dto.getPageSize());
        return result;
    }

    public PageResponseDTO<BackToArticleByMonResponseDTO> listBackToArticleByMonth(MyloanRequestDTO dto) {

        PageResponseDTO<BackToArticleByMonResponseDTO> result = new PageResponseDTO<>();
        Integer count = projectInvestorPlanMapperExt.listBackToArticleByMonthCount(dto.getUserId());
        result.setTotalCount(count);
        result.measureTotalPage(count, dto.getPageSize());
        if (count < 0) {
            result.setItems(new ArrayList<>());
            return result;
        }
        List<BackToArticleByMonResponseDTO> backToArticleByMonResponseDTOList = projectInvestorPlanMapperExt
                .listBackToArticleByMonth(dto.getUserId(), dto);
        result.setItems(backToArticleByMonResponseDTOList);
        return result;
    }

    public ContractResponseDTO queryContractByProjectId(MyProjectRequestDTO dto) {
        ContractResponseDTO contractResponseDTO = new ContractResponseDTO();
        Set<Long> set = new HashSet();
        set.add(dto.getProjectId());
        List<ProjectContract> list = projectContractMapperExt.queryFastLoanContractByProjectIdSet(set);

        /*ProjectContract projectContract = projectContractMapperExt
                .queryProjectContractByUserIdAndProjectIdAndContractType(dto.getUserId(), dto.getProjectId(),
                        FadadaContractTemplateEnum.TemplateTypeEnum.FAST_LOAN.getType());*/
        if (list == null || list.get(0) == null) {
            return contractResponseDTO;
        }
        contractResponseDTO.setViewUrl(list.get(0).getViewUrl());
        return contractResponseDTO;
    }

    @Autowired
    ProjectLocalService projectLocalService;

    public void cancelProject(LoanProjectRequestDTO dto) {
        ProjectFlowRequestDTO requestDTO = new ProjectFlowRequestDTO();
        requestDTO.setProjectId(dto.getProjectId());
        requestDTO.setSubStatus(ProjectSubStatusEnum.MISCARRY_CANCER_BORROWER);
        requestDTO.setRemark(dto.getRemark());

        projectLocalService.flow(requestDTO);

        /*Project projectUpdater = new Project();
        projectUpdater.setBorrowUserId(dto.getUserId());
        projectUpdater.setProjectId(dto.getProjectId());
        projectUpdater.setSubStatus(ProjectSubStatusEnum.MISCARRY_CANCER_BORROWER.getSubStatus());
        projectUpdater.setStatus(ProjectSubStatusEnum.MISCARRY_CANCER_BORROWER.getParentStatusEnum().getStatus());
        int num = projectMapperExt.updateByUserIdProjectSelective(projectUpdater);
        if (num > 0) {
            ProjectFlowed projectFlowed = new ProjectFlowed();
            projectFlowed.setCreateTime(new Date());
            projectFlowed.setFlowedReason(dto.getRemark());
            projectFlowed.setIsSystemFlowed(false);
            projectFlowed.setProjectId(dto.getProjectId());
            projectFlowed.setUserId(dto.getUserId());
            projectFlowed.setSyncStatus((byte)2); // 无需同步标的状态到存管
            projectFlowedMapper.insertSelective(projectFlowed);
        } else {
            log.error("标的状态更新失败");
            throw new BizException("TRD20002", "取消标的失败");
        }*/
    }

    @Transactional
    public Integer publishProject(LoanProjectRequestDTO dto) {
        Project projectUpdater = new Project();
        projectUpdater.setProjectId(dto.getProjectId());
        projectUpdater.setSubStatus(ProjectSubStatusEnum.COLLECTING_INIT.getSubStatus());
        projectUpdater.setStatus(ProjectSubStatusEnum.COLLECTING_INIT.getParentStatusEnum().getStatus());
        projectUpdater.setPublishTime(new Date());
        int num = projectMapperExt.updateByPrimaryKeySelective(projectUpdater);
        if (num < 1) {
            throw new BizException("TRD20003");
        }
        return projectUpdater.getSubStatus();
    }

    /**
     * 标的详情
     */
    public UserProjectStatisticResponseDTO queryProjectInfoDetail(MyProjectRequestDTO requestDTO) {
        UserProjectStatisticResponseDTO responseDTO = new UserProjectStatisticResponseDTO();
        Project project = projectMapperExt.selectByPrimaryKey(requestDTO.getProjectId());
        if (project == null) {
            throw new BizException("TRD20001");
        }
        log.info("标的详情###项目ID：projectId={}", requestDTO.getProjectId());
        List<ProjectInvestOrder> investOrderList = projectInvestOrderMapperExt.queryProjectInvestOrderListOrderByCreateTimeAscByProjectId(requestDTO.getProjectId());
        responseDTO.setRiskWarning(this.riskWarning);
        if (requestDTO.getUserId() != null) {
            UserIdentityInfoResponseDTO userIdentityInfo = userIdentityDubboService.get(requestDTO.getUserId());
            if (userIdentityInfo != null) {
                responseDTO.setRiskWarning(this.riskWarning
                        + (StringUtils.isBlank(userIdentityInfo.getName()) ? "" : userIdentityInfo.getName()));
            } else {
                //企业投资人
                SimpleOrgInfo orgInfo = organizationDubboService.getByOrgId(requestDTO.getUserId());
                responseDTO.setRiskWarning(orgInfo != null ? (this.riskWarning
                        + (StringUtils.isBlank(orgInfo.getOrganizationName()) ? "" : orgInfo.getOrganizationName())) : this.riskWarning);
            }
            if (project.getBorrowUserId().equals(requestDTO.getUserId())) {
                responseDTO.setTheBorrower(Byte.valueOf("1")); // 是否借款人(0:否 1：是)
                responseDTO.setAdditionalInvestment(Byte.valueOf("0")); // 是否追加投资(0:否 1：是)
            } else {
                responseDTO.setTheBorrower(Byte.valueOf("0")); // 是否借款人(0:否 1：是)
                investOrderList.forEach(o -> {
                    if (o.getUserId().equals(requestDTO.getUserId())) {
                        responseDTO.setAdditionalInvestment(Byte.valueOf("1")); // 是否追加投资(0:否 1：是)
                    }
                });
            }
            // 判断是否有5个待支付的投资订单
            int investingCount = projectInvestOrderMapperExt.selectInvestingCountByUserId(requestDTO.getUserId());
            if (investingCount >= 5) {
                Map<String, String> tradeConfigMap = tradeConfigService
                        .selectTradeConfigByEmuns(TradeConfigEnum.UNPAID_ORDER_WAITING_TIME);
                String unpaidOrderWaitingTime = tradeConfigMap
                        .get(TradeConfigEnum.UNPAID_ORDER_WAITING_TIME.getConfigKey());
                log.info("5个订单未支付等待时间###unpaidOrderWaitingTime={}", unpaidOrderWaitingTime);
                responseDTO.setInvestingCount(investingCount);
                responseDTO.setExpireTime(Integer.parseInt(unpaidOrderWaitingTime));
                responseDTO.setPopUpWindows(true);
            }
        }

        UserProjectStatisticResponseDTO dtoDb = projectMapperExt.selectSuccessAmount(project.getBorrowUserId());
        Integer finishCount = projectMapperExt.selectFinishCount(project.getBorrowUserId());
        // 用户历史逾期期数
        Integer overdueCount = projectBorrowerPlanNewMapperExt.countByUserIdForOverduePeriod(project.getBorrowUserId(), commonLocalService.getCurrentDate());
        /*
         * 考拉理财的投资记录数
         */
        if (ChannelCodeEnum.KAOLA.getChanelCode().equalsIgnoreCase(project.getChannelCode())) {
            Integer investmentRecord = kaoLaInvestorMapperExt.queryTotalInvestmentRecord(requestDTO.getProjectId());
            responseDTO.setInvestmentRecord(investmentRecord);
        } else {
            responseDTO.setInvestmentRecord(investOrderList.size());
        }
        responseDTO.setRiskWarning(responseDTO.getRiskWarning());
        responseDTO.setDeadline(project.getDeadline());
        responseDTO.setProjectId(project.getProjectId());
        responseDTO.setContractAmount(project.getContractAmount());
        responseDTO.setDeadlineUnit(project.getDeadlineUnit());
        responseDTO.setFinishCount(finishCount);
        responseDTO.setRemainingAmount(project.getContractAmount().subtract(project.getInvestedAmount()));
        responseDTO.setLoanArea(project.getLoanArea());
        responseDTO.setLoanCity(project.getLoanCity());
        responseDTO.setLoanUsage(project.getTitle().replaceAll("借款用途：","").replaceAll("借款用于",""));
        String publishTime = ProjectUtil.getProjectPublishtime(project);
        // 是否显示借款凭证
        LoanVoucherAudit loanVoucherAudit = loanVoucherAuditMapper.selectByUserIdProjectId(project.getBorrowUserId(), project.getProjectId());
        if (loanVoucherAudit != null
                && LoanVoucherEnum.IsShowEnum.SHOW.getValue().equals(loanVoucherAudit.getIsShow())
                && LoanVoucherEnum.AuditStatusEnum.PASS.getStatus().equals(loanVoucherAudit.getAuditStatus())) {
            responseDTO.setIsShowLoanVoucher(true);
        }
        //起投金额  递增金额 配置查询
        ProjectStartInvestAndIncreResponseDTO dto = this.getProjectStartInvestAndIncrement();

        responseDTO.setProjectIncrementalAmount(dto.getIncrementAmount());
        responseDTO.setProjectStartInvestAmount(dto.getStartInvestMoney());
        responseDTO.setPublishTime(publishTime);
        responseDTO.setRepaymentWay(project.getRepaymentType());
        responseDTO.setFullProjectTime(project.getFullSuccessTime());
        responseDTO.setSuccessAmount(dtoDb.getSuccessAmount());
        responseDTO.setSuccessCount(dtoDb.getSuccessCount());
        responseDTO.setRepetitionCount(dtoDb.getSuccessCount() == 0 ? 0 : (dtoDb.getSuccessCount() - 1));
        responseDTO.setOverdueCount(overdueCount);
        responseDTO.setStatus(project.getStatus());
        responseDTO.setSubStatus(project.getSubStatus());
        responseDTO.setChannelCode(project.getChannelCode());
        responseDTO.setProjectType(project.getType());
        responseDTO.setYearInterestRate(project.getBorrowRate());
        responseDTO.setCurrentPeriod(project.getDeadline());
        responseDTO.setCommonProblem(this.commonProblem);
        responseDTO.setUserId(project.getBorrowUserId());
        responseDTO.setGender(project.getBorrowGender());
        responseDTO.setHeadImage(project.getBorrowHeadImage());
        responseDTO.setNickName(project.getBorrowNickName());
        responseDTO.setNiiwooScore(project.getBorrowNiiwooScore());
        responseDTO.setCreditType(project.getCreditType());
        responseDTO.setBorrowerType(project.getBorrowerType());
        responseDTO.setLoanType(project.getLoanType());
        responseDTO.setLoanTypeDesc(LoanTypeEnum.enumOf(responseDTO.getLoanType()).getDesc());
        responseDTO.setProductReadme(ProductReadmeEnum.enumOf(LoanTypeEnum.enumOf(responseDTO.getLoanType())).getReadme());
        responseDTO.setIsMasterBorrower(project.getIsMasterBorrower());
        responseDTO.setAdvanceOverdueDays(project.getAdvanceOverdueDays());

        // 头像/昵称: 个人标:取借款人头像和昵称
        if (Byte.valueOf("1").equals(project.getBorrowerType()))  {
            Optional.ofNullable(userBasicInfoDubboService.selectUserBaseInfo(project.getBorrowUserId()))
                    .ifPresent(user -> {
                        responseDTO.setGender(user.getGender());
                        responseDTO.setHeadImage(user.getHeadImage());
                        responseDTO.setNickName(user.getNickName());
                        responseDTO.setNiiwooScore(user.getNiiwooScore());
                    });
        }

        // 标的提供方
        String provider = "你我金融";

        try {
        	SimpleOrgInfo orgInfo = organizationDubboService.getByOrgId(project.getOrgId());
            if (orgInfo != null && StringUtils.isNotBlank(orgInfo.getAbbreviation())) {
                provider = orgInfo.getAbbreviation();
            }
            responseDTO.setProvider(provider);

            // 标的提供方图标
            String providerLogo = "";
            if (orgInfo != null && StringUtils.isNotBlank(orgInfo.getLogo())) {
                providerLogo = orgInfo.getLogo();
            }
            responseDTO.setProviderLogo(providerLogo);            
		} catch (Exception e) {
		}

        // 担保方式H5页面
        String guaranteeModelH5Url = this.guaranteeModelH5Url + "?advanceOverdueDays=" + (project.getAdvanceOverdueDays() == null ? 0 : project.getAdvanceOverdueDays());

        responseDTO.setGuaranteeModelH5Url(guaranteeModelH5Url);

        //活动信息匹配
        if(Objects.nonNull(project.getActivityId())){
            InvestAddInterestRateConfig config = investAddInterestRateConfigMapperExt.selectByPrimaryKey(project.getActivityId());
            responseDTO.setActivityTitle(config.getTitle());
            responseDTO.setActivityAddInerest(project.getActivityRaiseRate());
        }
        //5.4.5新增剩余时间 （如果不为筹款中直接反回0）
        if(ProjectStatusEnum.COLLECTING.getStatus().equals(project.getStatus()) &&
                ProjectSubStatusEnum.COLLECTING_INIT.getSubStatus() == project.getSubStatus()){
            if(project.getInvestEndTime() != null){
                Long time = project.getInvestEndTime().getTime() - new Date().getTime();
                responseDTO.setRemainingTime(time < 0 ? 0 : time);
            }
        }
        responseDTO.setIsIntelligentInvestment(projectPackageLocalService.isPackagedProject(requestDTO.getProjectId()));
        return responseDTO;
    }

    private String getDateTimeStr(Date date) {
        String dateTimeStr = "";
        if (com.niiwoo.tripod.base.utils.DateUtils.isToday(date)) {
            dateTimeStr = FastDateFormat.getInstance(DatePatternConstant.HH_MM).format(date);
        } else {
            dateTimeStr = FastDateFormat.getInstance(DatePatternConstant.YYYY$MM$DD_HH_MM).format(date);
        }
        return dateTimeStr;
    }

    public ProjectStartInvestAndIncreResponseDTO getProjectStartInvestAndIncrement(){
        ProjectStartInvestAndIncreResponseDTO responseDTO = new ProjectStartInvestAndIncreResponseDTO();
        TradeConfigEnum keyInvest = TradeConfigEnum.PROJECT_START_INVESTMENT_MONEY;
        TradeConfigEnum keyIncrement = TradeConfigEnum.PROJECT_INCREMENTAL_AMOUNT;
        String startInvestMoney = redisTemplate.opsForValue().get(keyInvest.getConfigKey());
        String incrementIncrement = redisTemplate.opsForValue().get(keyIncrement.getConfigKey());
        if (Objects.isNull(startInvestMoney)) {
            startInvestMoney = tradeConfigLocalService.selectTradeConfigByEmun(keyInvest);
        }
        if (Objects.isNull(incrementIncrement)) {
            incrementIncrement = tradeConfigLocalService.selectTradeConfigByEmun(keyIncrement);
        }
        if(StringUtils.isBlank(startInvestMoney)||StringUtils.isBlank(incrementIncrement)){
            throw new BizException("TRD21002","起投金额递增金额未配置");
        }
        responseDTO.setStartInvestMoney(new BigDecimal(startInvestMoney));
        responseDTO.setIncrementAmount(new BigDecimal(incrementIncrement));
        return responseDTO;
    }
    /**
     * 我要投资-标的详情-回款计划 查询标的回款计划
     * 1.1用户查询某一标的回款计划 如果用户投资了该标的且支付成功，则使用该用户投资此标的支付成功总金额计算回款计划(暂时不计算使用加息券)
     * 1.2用户查询某一标的回款计划 用户未投资该标的或未支付成功，则使用举例金额计算回款计划
     *
     * @param userId
     * @param projectId
     * @return
     */
    public ProjectInvestorPlanResponseDTO queryProjectInvestorPlan(String userId, Long projectId) {
        log.info("回款计划###项目ID：projectId={}", projectId);
        log.info("回款计划###userId={}", userId);
        if (projectId == null || projectId == 0) {
            throw new BizException("TRD10012");
        }
        Project project = projectMapperExt.selectByPrimaryKey(projectId);
        ProjectInvestorPlanResponseDTO responseDTO = new ProjectInvestorPlanResponseDTO();
        BigDecimal amount = BigDecimal.ZERO;
        BigDecimal receivableTotalAmount = BigDecimal.ZERO; // 预计回款总额
        BigDecimal interestTotal = BigDecimal.ZERO; // 利息总计

        List<ProjectInvestOrder> projectInvestOrderList = projectInvestOrderMapperExt.selectInvestedByProjectIdAndUserId(userId, projectId);
        // 用户没有投资该标的支付成功的投资订单取举例金额
        if (projectInvestOrderList == null || projectInvestOrderList.isEmpty()) {
            Map<String, String> tradeConfigMap = tradeConfigService.selectTradeConfigByEmuns(TradeConfigEnum.REIMBURSEMENT_PLAN_EXAMPLE_MONEY);
            String reimbursementPlanExampleMoney = tradeConfigMap.get(TradeConfigEnum.REIMBURSEMENT_PLAN_EXAMPLE_MONEY.getConfigKey());
            amount = new BigDecimal(reimbursementPlanExampleMoney);
            responseDTO.setIsInvest(Byte.valueOf("0")); // 用户是否投资(0.未投标 1.已投标 )
            log.info("回款计划举例金额###reimbursementPlanExampleMoney={}", reimbursementPlanExampleMoney);
        } else {
            for (ProjectInvestOrder projectInvestOrder : projectInvestOrderList) {
                amount = amount.add(projectInvestOrder.getAmount());
            }
            responseDTO.setIsInvest(Byte.valueOf("1")); // 用户是否投资(0.未投标 1.已投标 )
        }

        // 用户已投资，并且标的状态为3:还款中 4：已结清，则查询用户投资回款计划表进行展示
        if ((project.getStatus().equals(ProjectStatusEnum.FINISH.getStatus()) || project.getStatus().equals(ProjectStatusEnum.REPAYING.getStatus()))
                && responseDTO.getIsInvest().equals(Byte.valueOf("1"))) {
            boolean addProjectInvestorPlan = true;
            List<ProjectInvestorPlan> investorPlanList = new ArrayList<>();
            List<ProjectInvestorPlan> projectInvestorPlanList = projectInvestorPlanMapperExt.listProjectInvestorPlan(projectId, userId);
            for (ProjectInvestorPlan projectInvestorPlan : projectInvestorPlanList) {
                ProjectInvestorPlan plan = new ProjectInvestorPlan();
                plan.setCapital(projectInvestorPlan.getCapital());
                plan.setInterest(projectInvestorPlan.getInterest());
                plan.setReceivedCapital(projectInvestorPlan.getReceivedCapital());
                plan.setReceivedInterest(projectInvestorPlan.getReceivedInterest());
                plan.setCurrentPeriod(projectInvestorPlan.getCurrentPeriod());
                plan.setReceivedStatus(projectInvestorPlan.getReceivedStatus());
                plan.setOverTime(projectInvestorPlan.getOverTime());
                plan.setReceivedDate(projectInvestorPlan.getReceivedDate());
                if (investorPlanList.size() > 0) {
                    for (ProjectInvestorPlan investorPlan : investorPlanList) {
                        if (projectInvestorPlan.getCurrentPeriod().equals(investorPlan.getCurrentPeriod())) {
                            investorPlan.setInterest(investorPlan.getInterest().add(projectInvestorPlan.getInterest()));
                            investorPlan.setCapital(investorPlan.getCapital().add(projectInvestorPlan.getCapital()));
                            investorPlan.setReceivedCapital(investorPlan.getReceivedCapital().add(projectInvestorPlan.getReceivedCapital()));
                            investorPlan.setReceivedInterest(investorPlan.getReceivedInterest().add(projectInvestorPlan.getReceivedInterest()));
                            addProjectInvestorPlan = false;
                        } else {
                            addProjectInvestorPlan = true;
                        }
                    }
                }
                if (addProjectInvestorPlan)
                    investorPlanList.add(plan);
            }
            for (ProjectInvestorPlan projectInvestorPlan : investorPlanList) {
                ProjectInvestorPlanResponseDTO.ReceivableRecords receivableRecords = new ProjectInvestorPlanResponseDTO.ReceivableRecords();
                if (InvestorPlanReceivedStatusEnum.NON_RECEIVE.getCode().equals(projectInvestorPlan.getReceivedStatus())) {
                    receivableRecords.setReceivableAmount(projectInvestorPlan.getCapital());
                    receivableRecords.setTotalAmount(projectInvestorPlan.getCapital().add(projectInvestorPlan.getInterest()));
                    receivableRecords.setReceivableRate(projectInvestorPlan.getInterest());
                    interestTotal = interestTotal.add(projectInvestorPlan.getInterest());
                } else {
                    receivableRecords.setReceivableAmount(projectInvestorPlan.getReceivedCapital());
                    receivableRecords.setTotalAmount(projectInvestorPlan.getReceivedCapital().add(projectInvestorPlan.getReceivedInterest()));
                    receivableRecords.setReceivableRate(projectInvestorPlan.getReceivedInterest());
                    interestTotal = interestTotal.add(projectInvestorPlan.getReceivedInterest());
                }
                receivableRecords.setReceiveDate(DateFormatUtils.format(projectInvestorPlan.getReceivedDate(), DatePatternConstant.YYYY_MM_DD));
                responseDTO.getReceivableRecords().add(receivableRecords);
                receivableTotalAmount = receivableTotalAmount.add(receivableRecords.getTotalAmount());
            }
            responseDTO.setFullSuccessTime(DateFormatUtils.format(project.getFullSuccessTime(), DatePatternConstant.YYYY_MM_DD));
        } else {
            List<RepaymentPlanDTO> repaymentPlanDTOList = borrowerInvestorRepaymentContext.getBorrowerRepaymentPlan(
                    RepaymentTypeEnum.enumOf(project.getRepaymentType()), amount, project.getBorrowRate(),
                    project.getDeadline(), PeriodUnitEnum.enumOf(project.getDeadlineUnit()),
                    project.getFullSuccessTime() == null ? new Date() : project.getFullSuccessTime(), project.getLeastCalculateInterestDays());
            for (RepaymentPlanDTO repaymentPlanDTO : repaymentPlanDTOList) {
                ProjectInvestorPlanResponseDTO.ReceivableRecords receivableRecords = new ProjectInvestorPlanResponseDTO.ReceivableRecords();
                receivableRecords.setTotalAmount(repaymentPlanDTO.getPrincipalInterest());
                receivableRecords.setReceivableAmount(repaymentPlanDTO.getPrincipal());
                receivableRecords.setReceivableRate(repaymentPlanDTO.getInterest());
                String receiveDate = DateFormatUtils.format(repaymentPlanDTO.getRefundDate(), DatePatternConstant.YYYY_MM_DD);
                receivableRecords.setReceiveDate(receiveDate);
                responseDTO.getReceivableRecords().add(receivableRecords);
                interestTotal = interestTotal.add(repaymentPlanDTO.getInterest());
                receivableTotalAmount = receivableTotalAmount.add(repaymentPlanDTO.getPrincipalInterest());
            }
        }
        if (ProjectSubStatusEnum.COLLECTING_INIT == ProjectSubStatusEnum.enumOf(project.getSubStatus())) {
            responseDTO.setFullSuccessTime(DateFormatUtils.format(new Date(), DatePatternConstant.YYYY_MM_DD));
            responseDTO.setProjectState(Byte.valueOf("0")); // 标的状态(0.未满标 1.已满标)
        } else {
            responseDTO.setFullSuccessTime(DateFormatUtils.format(project.getFullSuccessTime(), DatePatternConstant.YYYY_MM_DD));
            responseDTO.setProjectState(Byte.valueOf("1")); // 标的状态(0.未满标 1.已满标)
        }
        responseDTO.setInvestAmount(amount);
        responseDTO.setInterestTotal(interestTotal);
        responseDTO.setReceivableTotalAmount(receivableTotalAmount);
        return responseDTO;
    }

    /**
     * 查询全量还款计划
     *
     * @param projectId
     * @param userId
     * @return
     */
    public QueryRepaymentPlanResponseDTO queryRepaymentPlanDetail(Long projectId, String userId) {
        Assert.notNull(projectId, "queryRepaymentPlan projectId is null");
        Assert.notNull(userId, "queryRepaymentPlan userId  is null");
        // 标的信息
        Project project = Optional.ofNullable(projectMapperExt.selectByPrimaryKey(projectId)).orElseThrow(() -> new BizException("TRD20001"));

        // 还款计划（按期数升序排序）
        List<ProjectBorrowerPlanNew> projectBorrowerPlanNewList = Optional.ofNullable(projectBorrowerPlanNewMapperExt.selectByProjectId(projectId))
                .orElseThrow(() -> new BizException("TRD20005"));

        // 还款计划
        List<ProjectBorrowerPlanReponseDTO> borrowerPlanReponseDTOList = new ArrayList<ProjectBorrowerPlanReponseDTO>();

        for (ProjectBorrowerPlanNew projectBorrowerPlanNew : projectBorrowerPlanNewList) {
            ProjectBorrowerPlanNewDetailDTO projectBorrowerPlanNewDetailDTO = refundCommonService.bulidProjectBorrowerPlanNewAmount(projectBorrowerPlanNew.getId());

            ProjectBorrowerPlanReponseDTO borrowerPlanReponseDTO = new ProjectBorrowerPlanReponseDTO();

            borrowerPlanReponseDTO.setCurrentPeriod(projectBorrowerPlanNew.getPeriod());
            borrowerPlanReponseDTO.setTotalPeriod(projectBorrowerPlanNew.getTotalPeriod());
            borrowerPlanReponseDTO.setRefundDate(DateFormatUtils.format(projectBorrowerPlanNew.getRefundDate(), DatePatternConstant.YYYY_MM_DD));
            borrowerPlanReponseDTO.setOverTime(projectBorrowerPlanNew.getOverDate()); // 结清时间
            borrowerPlanReponseDTO.setRefundStatus(projectBorrowerPlanNew.getStatus());

            // 当期金额信息

            // 当期应还总金额
            BigDecimal needRepayAmount = projectBorrowerPlanNewDetailDTO.getCapital().add(projectBorrowerPlanNewDetailDTO.getInterest())
                    .add(projectBorrowerPlanNewDetailDTO.getPenaltyFee()).add(projectBorrowerPlanNewDetailDTO.getManagementFee()).add(projectBorrowerPlanNewDetailDTO.getGuaranteeFee());
            // 当期已还款金额
            BigDecimal paidAmount = projectBorrowerPlanNewDetailDTO.getRefundedCapital().add(projectBorrowerPlanNewDetailDTO.getRefundedInterest())
                    .add(projectBorrowerPlanNewDetailDTO.getRefundedPenaltyFee()).add(projectBorrowerPlanNewDetailDTO.getRefundedManagementFee()).add(projectBorrowerPlanNewDetailDTO.getRefundedGuaranteeFee());

            borrowerPlanReponseDTO.setCapital(projectBorrowerPlanNewDetailDTO.getCapital());
            borrowerPlanReponseDTO.setInterest(projectBorrowerPlanNewDetailDTO.getInterest());
            borrowerPlanReponseDTO.setManagementFee(projectBorrowerPlanNewDetailDTO.getManagementFee());
            borrowerPlanReponseDTO.setPenaltyFee(projectBorrowerPlanNewDetailDTO.getPenaltyFee());
            borrowerPlanReponseDTO.setGuaranteeFee(projectBorrowerPlanNewDetailDTO.getGuaranteeFee());
            borrowerPlanReponseDTO.setRefundedCapital(projectBorrowerPlanNewDetailDTO.getRefundedCapital());
            borrowerPlanReponseDTO.setRefundedInterest(projectBorrowerPlanNewDetailDTO.getRefundedInterest());
            borrowerPlanReponseDTO.setRefundedManagementFee(projectBorrowerPlanNewDetailDTO.getRefundedManagementFee());
            borrowerPlanReponseDTO.setRefundedPenaltyFee(projectBorrowerPlanNewDetailDTO.getRefundedPenaltyFee());
            borrowerPlanReponseDTO.setRefundedGuaranteeFee(projectBorrowerPlanNewDetailDTO.getRefundedGuaranteeFee());

            borrowerPlanReponseDTO.setNeedRepayAmount(needRepayAmount);
            borrowerPlanReponseDTO.setPaidAmount(paidAmount);

            // 逾期与坏帐
            BorrowerPlanOverdueDTO borrowerPlanOverdueDTO = refundCommonService.getBorrowerPlanOverdueInfo(projectBorrowerPlanNew, project);
            borrowerPlanReponseDTO.setIsOverdue(borrowerPlanOverdueDTO.getIsOverdue());
            borrowerPlanReponseDTO.setIsBadDebt(borrowerPlanOverdueDTO.getIsBadloan());
            borrowerPlanReponseDTO.setOverdueDay(borrowerPlanOverdueDTO.getOverdueDay());
            if (ChannelCodeEnum.KAOLA.getChanelCode().equalsIgnoreCase(project.getChannelCode())) {
                borrowerPlanReponseDTO.setOverdueDay(kaoLaLiCaiRepaymentService.getKaolaOverdueDays(projectBorrowerPlanNew.getRefundDate()));
            }
            if (borrowerPlanOverdueDTO.getIsOverdue()) {
                borrowerPlanReponseDTO.setOverdueDesc("逾期" + borrowerPlanOverdueDTO.getOverdueDay() + "天，罚息：￥" + projectBorrowerPlanNewDetailDTO.getPenaltyFee());
            }

            // 是否提前结清
            if (BorrowerPlanRefundStatusEnum.OVER_DEBT_REPAYMENT.getCode().byteValue() == projectBorrowerPlanNew.getStatus()) {
                // 标记已提前还款
                borrowerPlanReponseDTO.setIsEarlySettlement(true);
                // 提前结清以已还利息为准
                borrowerPlanReponseDTO.setInterest(projectBorrowerPlanNewDetailDTO.getRefundedInterest());
            } else {
                borrowerPlanReponseDTO.setIsEarlySettlement(false);
            }

            // 最早可还款时间（非一期最早还款为上一期还期日期）
            if (projectBorrowerPlanNew.getPeriod() != 1) {
                ProjectBorrowerPlanNew previousProjectBorrowPlanNew = projectBorrowerPlanNewMapperExt.selectByProjectAndPeriod(projectId, projectBorrowerPlanNew.getPeriod() - 1);
                borrowerPlanReponseDTO.setEarlistRepayTime(previousProjectBorrowPlanNew.getRefundDate());
            } else {
                Date earlistRepayTime = new DateTime(projectBorrowerPlanNew.getRefundDate()).minusMonths(1).toDate();
                borrowerPlanReponseDTO.setEarlistRepayTime(earlistRepayTime);
            }
            borrowerPlanReponseDTOList.add(borrowerPlanReponseDTO);
        }

        // 返回对象
        QueryRepaymentPlanResponseDTO queryRepaymentPlanResponseDTO = new QueryRepaymentPlanResponseDTO();
        queryRepaymentPlanResponseDTO.setRepaymentType(project.getRepaymentType());
        queryRepaymentPlanResponseDTO.setBizType(project.getType());
        queryRepaymentPlanResponseDTO.setBorrowerPlanReponseDTOList(borrowerPlanReponseDTOList);
        return queryRepaymentPlanResponseDTO;
    }

    /**
     * 查询我的还款计划(只查询今天该还款的还款计划)
     *
     * @return
     */
    public List<ProjectBorrowerPlanDTO> queryMyLoanPlanByToday(String userId) {
        List<ProjectBorrowerPlanDTO> projectBorrowerPlanDTOList = Lists.newArrayList();

        String today = FastDateFormat.getInstance("yyyy-MM-dd").format(DateTime.now().toDate());

        List<ProjectBorrowerPlanNew> projectBorrowerPlanNewList = projectBorrowerPlanNewMapperExt.selectByUserIdForToday(userId, today);
        if (CollectionUtils.isNotEmpty(projectBorrowerPlanNewList)) {
            projectBorrowerPlanNewList.forEach(projectBorrowerPlanNew -> {
                ProjectBorrowerPlanDTO projectBorrowerPlanDTO = new ProjectBorrowerPlanDTO();

                ProjectBorrowerPlanNewDetailDTO projectBorrowerPlanNewDetailDTO = refundCommonService.bulidProjectBorrowerPlanNewAmount(projectBorrowerPlanNew.getId());

                projectBorrowerPlanDTO.setId(projectBorrowerPlanNew.getId());
                projectBorrowerPlanDTO.setProjectId(projectBorrowerPlanNew.getProjectId());
                projectBorrowerPlanDTO.setCurrentPeriod(projectBorrowerPlanNew.getPeriod());
                projectBorrowerPlanDTO.setTotalPeriod(projectBorrowerPlanNew.getTotalPeriod());
                projectBorrowerPlanDTO.setRefundDate(projectBorrowerPlanNew.getRefundDate());
                projectBorrowerPlanDTO.setCapital(projectBorrowerPlanNewDetailDTO.getCapital());
                projectBorrowerPlanDTO.setInterest(projectBorrowerPlanNewDetailDTO.getInterest());
                projectBorrowerPlanDTO.setPenaltyFee(projectBorrowerPlanNewDetailDTO.getPenaltyFee());
                projectBorrowerPlanDTO.setManagementFee(projectBorrowerPlanNewDetailDTO.getManagementFee());
                projectBorrowerPlanDTO.setRefundedCapital(projectBorrowerPlanNewDetailDTO.getRefundedCapital());
                projectBorrowerPlanDTO.setRefundedInterest(projectBorrowerPlanNewDetailDTO.getRefundedInterest());
                projectBorrowerPlanDTO.setRefundedManagementFee(projectBorrowerPlanNewDetailDTO.getRefundedManagementFee());
                projectBorrowerPlanDTO.setYearMouth(new DateTime(projectBorrowerPlanNew.getRefundDate()).toString("yyyyMM"));
                projectBorrowerPlanDTO.setRefundStatus(projectBorrowerPlanNew.getStatus());
                projectBorrowerPlanDTO.setOverTime(projectBorrowerPlanNew.getOverDate());
                projectBorrowerPlanDTO.setCreateTime(projectBorrowerPlanNew.getCreateTime());
                projectBorrowerPlanDTO.setUpdateTime(projectBorrowerPlanNew.getUpdateTime());

                projectBorrowerPlanDTOList.add(projectBorrowerPlanDTO);
            });
        }

        return projectBorrowerPlanDTOList;
    }

    /**
     * 查询我的逾期还款标的
     *
     * @return
     */
    public List<ProjectBorrowerSummaryDTO> queryMyLoanOverdue(String userId) {
        return JSONArray.parseArray(JSON.toJSONString(projectBorrowerSummaryMapperExt.queryMyLoanOverdue(userId)),
                ProjectBorrowerSummaryDTO.class);
    }

    public Integer isExistOverdueAndRepaymentProject(String userId) {
        log.info("isExistOverdueAndRepaymentProject.userId={}", userId);
        int overdueProjectCount = 0;
        int repaymentsProjectCount = 0;
        try {
            overdueProjectCount = projectBorrowerSummaryMapperExt.getOverdueProjectCount(userId);
            log.info("isExistOverdueAndRepaymentProject.userId={},overdueProjectCount={}", userId, overdueProjectCount);
            FastDateFormat fastDateFormat = FastDateFormat.getInstance("yyyy-MM-dd");
            Date repaymentDate = fastDateFormat.parse(fastDateFormat.format(DateTime.now().plusDays(7).toDate()));
            repaymentsProjectCount = projectBorrowerSummaryMapperExt.getRepaymentsProjectCount(userId, repaymentDate);
            log.info("isExistOverdueAndRepaymentProject.userId={},repaymentsProjectCount={}", userId,
                    repaymentsProjectCount);
        } catch (ParseException e) {
            log.error("", e);
            throw new RuntimeException(e);
        }
        return overdueProjectCount + repaymentsProjectCount;
    }

    public LoanVoucherAuditInfoQueryResponseDTO loanVoucherAuditInfoQuery(LoanVoucherAuditInfoQueryRequestDTO requestDTO) {
        String loginUserId = requestDTO.getLoginUserId(); //登录用户ID
        String borrowUserId = requestDTO.getBorrowUserId(); //借款人用户ID
        Long projectId = requestDTO.getProjectId();
        LoanVoucherAudit loanVoucherAudit = loanVoucherAuditMapper.selectByUserIdProjectId(borrowUserId, projectId);
        if (loanVoucherAudit == null) {
            return null;
        }
        boolean isSelfQuery = this.isSelfQuery(borrowUserId, loginUserId); //是否为本人查询

        //后台配置不展示借款凭证信息，则返回空（自己查看自己的借款凭证除外）
        if (LoanVoucherEnum.IsShowEnum.NO_SHOW.getValue().equals(loanVoucherAudit.getIsShow())
                && !isSelfQuery) {
            return null;
        }

        LoanVoucherAuditInfoQueryResponseDTO respDTO = new LoanVoucherAuditInfoQueryResponseDTO();
        respDTO.setLoanDesc(loanVoucherAudit.getLoanDesc());
        respDTO.setAuditStatus(loanVoucherAudit.getAuditStatus());
        respDTO.setAuditDesc(loanVoucherAudit.getAuditDesc());
        respDTO.setIsShow(loanVoucherAudit.getIsShow());
        //审核状态没有通过，则无需返回图片信息
        if (!LoanVoucherEnum.AuditStatusEnum.PASS.getStatus().equals(loanVoucherAudit.getAuditStatus())) {
            return respDTO;
        }

        List<LoanVoucherImg> loanVoucherImgList = loanVoucherImgMapper.selectByUserIdProjectIdVoucherAuditNo(borrowUserId, projectId, loanVoucherAudit.getVoucherAuditNo());
        if (CollectionUtils.isEmpty(loanVoucherImgList)) {
            return respDTO;
        }

        List<LoanVoucherAuditInfoQueryResponseDTO.LoanVoucherAuditImgResponseDTO> loanVoucherImgRespList = new ArrayList<>();
        for (LoanVoucherImg img : loanVoucherImgList) {
            String imgUrl = img.getImgUrl();//图片地址
            String imgReleaseUrl = img.getImgReleaseUrl();//图片打码后地址
            String imgThumbnailUrl = img.getImgThumbnailUrl();//图片缩略地址
            String imgReleaseThumbnailUrl = img.getImgReleaseThumbnailUrl();//图片打码后的缩略地址

            LoanVoucherAuditInfoQueryResponseDTO.LoanVoucherAuditImgResponseDTO impRespDTO = new LoanVoucherAuditInfoQueryResponseDTO.LoanVoucherAuditImgResponseDTO();

            impRespDTO.setImgUrl(this.getImgUrl(isSelfQuery, imgUrl, imgReleaseUrl));
            impRespDTO.setImgThumbnailUrl(this.getImgUrl(isSelfQuery, imgThumbnailUrl, imgReleaseThumbnailUrl));
            loanVoucherImgRespList.add(impRespDTO);
        }
        respDTO.setLoanVoucherImgList(loanVoucherImgRespList);

        return respDTO;
    }

    private String getImgUrl(boolean isSelfQuery, String imgUrl, String imgReleaseUrl) {
        if (isSelfQuery) {
            return StringUtils.isNoneEmpty(imgUrl) ? imgUrl : imgReleaseUrl;
        }
        return StringUtils.isNoneEmpty(imgReleaseUrl) ? imgReleaseUrl : imgUrl;
    }

    private boolean isSelfQuery(String borrowUserId, String loginUserId) {
        if (StringUtils.isEmpty(loginUserId)) {
            return false;
        }
        return loginUserId.equals(borrowUserId);
    }

    @Transactional(rollbackFor = Exception.class)
    public void loanVoucherInfoSave(LoanVoucherSubmitRequestDTO requestDTO) {
        //this.check(requestDTO);
        Long voucherAuditNo = snowflakeIdWorker.nextId();
        loanVoucherAuditInfoSave(requestDTO, voucherAuditNo);
        loanVoucherImgInfoSave(requestDTO, voucherAuditNo);
    }

    public void loanVoucherAuditInfoSave(LoanVoucherSubmitRequestDTO requestDTO, Long voucherAuditNo) {
        String userId = requestDTO.getUserId();
        Long projectId = requestDTO.getProjectId();

        Date now = new Date();
        LoanVoucherAudit loanVoucherAudit = new LoanVoucherAudit();
        loanVoucherAudit.setUserId(userId);
        loanVoucherAudit.setProjectId(projectId);
        loanVoucherAudit.setVoucherAuditNo(voucherAuditNo);
        loanVoucherAudit.setLoanDesc(requestDTO.getLoanDesc());
        loanVoucherAudit.setAuditStatus(LoanVoucherEnum.AuditStatusEnum.IN_AUDIT.getStatus());
        loanVoucherAudit.setIsShow(LoanVoucherEnum.IsShowEnum.SHOW.getValue());
        loanVoucherAudit.setCreateTime(now);
        loanVoucherAudit.setUpdateTime(now);

        LoanVoucherAudit oldLoanVoucherAudit = loanVoucherAuditMapper.selectByUserIdProjectId(userId, projectId);
        if (oldLoanVoucherAudit == null) {
            loanVoucherAudit.setId(snowflakeIdWorker.nextId());
            loanVoucherAuditMapper.insertSelective(loanVoucherAudit);
        } else {
            //如果存在，则先拷贝数据至历史记录表中
            //copyLoanVoucherAuditInfoToHis(oldLoanVoucherAudit);
            loanVoucherAudit.setId(oldLoanVoucherAudit.getId());
            loanVoucherAuditMapper.updateByUserIdProjectId(loanVoucherAudit);
        }
    }

    public void copyLoanVoucherAuditInfoToHis(LoanVoucherAudit loanVoucherAudit) {
        Date now = new Date();
        LoanVoucherAuditHis hisDTO = new LoanVoucherAuditHis();
        BeanUtils.copyProperties(loanVoucherAudit, hisDTO);
        hisDTO.setId(snowflakeIdWorker.nextId());
        loanVoucherAudit.setCreateTime(now);
        loanVoucherAudit.setUpdateTime(now);
        loanVoucherAuditHisMapper.insertSelective(hisDTO);
    }

    public void loanVoucherImgInfoSave(LoanVoucherSubmitRequestDTO requestDTO, Long voucherAuditNo) {
        String userId = requestDTO.getUserId();
        Long projectId = requestDTO.getProjectId();
        List<LoanVoucherSubmitRequestDTO.LoanVoucherImgRequestDTO> loanVoucherImgList = requestDTO.getLoanVoucherImgList();
        if (CollectionUtils.isEmpty(loanVoucherImgList)) {
            return;
        }
        for (int i = 0; i < loanVoucherImgList.size(); i++) {
            Date now = new Date();
            LoanVoucherSubmitRequestDTO.LoanVoucherImgRequestDTO imgDTO = loanVoucherImgList.get(i);
            LoanVoucherImg loanVoucherImg = new LoanVoucherImg();
            loanVoucherImg.setId(snowflakeIdWorker.nextId());
            loanVoucherImg.setUserId(userId);
            loanVoucherImg.setProjectId(projectId);
            loanVoucherImg.setVoucherAuditNo(voucherAuditNo);
            loanVoucherImg.setImgUrl(imgDTO.getImgUrl());
            loanVoucherImg.setImgThumbnailUrl(imgDTO.getImgThumbnailUrl());
            loanVoucherImg.setOrderNo((byte) i);
            loanVoucherImg.setCreateTime(now);
            loanVoucherImg.setUpdateTime(now);
            loanVoucherImgMapper.insertSelective(loanVoucherImg);
        }
    }

    /**
     * 查询用户待还本金，本金包括：还款中 + 筹款中 + 审核中
     * 此接口用来给机构开户时查询使用
     *
     * @param userId
     * @return
     */
    public BigDecimal queryUserToPayCapital(String userId) {
        // 查询还款计划待还本金
        BigDecimal borrpwerPlanToReturned = projectBorrowerPlanDetailMapperExt.countToPayMoneyByUserIdAndFeeType(userId, FeeTypeEnum.CAPITAL.getValue());
        borrpwerPlanToReturned = borrpwerPlanToReturned == null ? BigDecimal.ZERO : borrpwerPlanToReturned;

        // 查询审核中和筹款中的项目
        BigDecimal checkingAmount = BigDecimal.ZERO;
        BigDecimal collectingAmount = BigDecimal.ZERO;
        List<ProjectStatusEnum> statusList = new ArrayList<>();
        statusList.add(ProjectStatusEnum.CHECKING);
        statusList.add(ProjectStatusEnum.COLLECTING);
        List<Project> checkingProjects = projectMapperExt.listProjectByChannelCodeAndStatus(userId, null, statusList, null);
        for (Project project : checkingProjects) {
            if (project.getStatus().intValue() == ProjectStatusEnum.CHECKING.getStatus().intValue()) {
                checkingAmount = checkingAmount.add(project.getContractAmount());
            } else {
                collectingAmount = collectingAmount.add(project.getContractAmount());
            }
        }
        // 待还本金加上筹款中本金
        borrpwerPlanToReturned = borrpwerPlanToReturned.add(collectingAmount);

        // 判断审核中金额是否>0
        if (checkingAmount.compareTo(BigDecimal.ZERO) > 0) {
            String captialConfigStr = tradeConfigService.selectTradeConfigByEmun(TradeConfigEnum.ORG_PUSH_PROJECT_CAPTIAL_CONFIG);
            if (StringUtils.isBlank(captialConfigStr)) {
                captialConfigStr = "15000";
            }
            borrpwerPlanToReturned = borrpwerPlanToReturned.add(new BigDecimal(captialConfigStr));
        }
        return borrpwerPlanToReturned;
    }
}